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') 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 40465293cd780aa82dcae75dfcfb1449d8c0561e Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 3 Mar 2021 18:37:49 -0500 Subject: c++: ICE with real-to-int conversion in template [PR97973] In this test we are building a call in a template, but since neither the function nor any of its arguments are dependent, we go down the normal path in finish_call_expr. convert_arguments sees that we're binding a reference to int to double and therein convert_to_integer creates a FIX_TRUNC_EXPR. Later, we call check_function_arguments which folds the arguments, and, in a template, fold_for_warn calls fold_non_dependent_expr. But tsubst_copy_and_build should not see a FIX_TRUNC_EXPR (see the patch discussed in ) or we crash. So let's not create a FIX_TRUNC_EXPR in a template in the first place and instead use IMPLICIT_CONV_EXPR. gcc/cp/ChangeLog: PR c++/97973 * call.c (conv_unsafe_in_template_p): New. (convert_like): Use it. gcc/testsuite/ChangeLog: PR c++/97973 * g++.dg/conversion/real-to-int1.C: New test. --- gcc/cp/call.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 29f4b50..390b8aa 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8048,6 +8048,27 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, return expr; } +/* Return true if converting FROM to TO is unsafe in a template. */ + +static bool +conv_unsafe_in_template_p (tree to, tree from) +{ + /* Converting classes involves TARGET_EXPR. */ + if (CLASS_TYPE_P (to) || CLASS_TYPE_P (from)) + return true; + + /* Converting real to integer produces FIX_TRUNC_EXPR which tsubst + doesn't handle. */ + if (SCALAR_FLOAT_TYPE_P (from) && INTEGRAL_OR_ENUMERATION_TYPE_P (to)) + return true; + + /* Converting integer to real isn't a trivial conversion, either. */ + if (INTEGRAL_OR_ENUMERATION_TYPE_P (from) && SCALAR_FLOAT_TYPE_P (to)) + return true; + + return false; +} + /* Wrapper for convert_like_internal that handles creating IMPLICIT_CONV_EXPR. */ @@ -8064,7 +8085,7 @@ convert_like (conversion *convs, tree expr, tree fn, int argnum, tree conv_expr = NULL_TREE; if (processing_template_decl && convs->kind != ck_identity - && (CLASS_TYPE_P (convs->type) || CLASS_TYPE_P (TREE_TYPE (expr)))) + && conv_unsafe_in_template_p (convs->type, TREE_TYPE (expr))) { conv_expr = build1 (IMPLICIT_CONV_EXPR, convs->type, expr); if (convs->kind != ck_ref_bind) -- cgit v1.1 From 19ac7c94b2ff9e6e289b30989a9339cb7f76a86a Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 18 Mar 2021 00:16:24 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0f91414..f2f7f45 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,18 @@ +2021-03-17 Marek Polacek + + PR c++/97973 + * call.c (conv_unsafe_in_template_p): New. + (convert_like): Use it. + +2021-03-17 Anthony Sharp + Jason Merrill + + * 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. + 2021-03-16 Jason Merrill * tree.c (cp_tree_equal): Use real_identical. -- cgit v1.1 From 3bcf19215d88e6ec33d283352c52005f02dbc784 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Tue, 16 Mar 2021 13:26:09 +0100 Subject: coroutines: init struct members to NULL gcc/cp/ChangeLog: PR c++/99617 * coroutines.cc (struct var_nest_node): Init then_cl and else_cl to NULL. --- gcc/cp/coroutines.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 51984ef..dbd703a 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2805,7 +2805,7 @@ struct var_nest_node { var_nest_node () = default; var_nest_node (tree v, tree i, var_nest_node *p, var_nest_node *n) - : var(v), init(i), prev(p), next(n) + : var(v), init(i), prev(p), next(n), then_cl (NULL), else_cl (NULL) { if (p) p->next = this; -- cgit v1.1 From 0cc218d42c241ed286cc5af9fb7d2e45386f7a24 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Fri, 26 Feb 2021 10:21:02 +0000 Subject: Objective-C++ : Fix handling of unnamed message parms [PR49070]. When we are parsing an Objective-C++ message, a colon is a valid terminator for a assignment-expression. That is: [receiver meth:x:x:x:x]; Is a valid, if somewhat unreadable, construction; corresponding to a method declaration like: - (id) meth:(id)arg0 :(id)arg1 :(id)arg2 :(id)arg3; Where three of the message params have no selector name. If fact, although it might be unintentional, Objective-C/C++ can accept message selectors with all the parms unnamed (this applies to the clang implementation too, which is taken as the reference for the language). For regular C++, the pattern x:x is not valid in that position an an error is emitted with a fixit for the expected scope token. If we simply made that error conditional on !c_dialect_objc() that would regress Objective-C++ diagnostics for cases outside a message selector, so we add a state flag for this. gcc/cp/ChangeLog: PR objc++/49070 * parser.c (cp_debug_parser): Add Objective-C++ message state flag. (cp_parser_nested_name_specifier_opt): Allow colon to terminate an assignment-expression when parsing Objective- C++ messages. (cp_parser_objc_message_expression): Set and clear message parsing state on entry and exit. * parser.h (struct cp_parser): Add a context flag for Objective-C++ message state. gcc/testsuite/ChangeLog: PR objc++/49070 * obj-c++.dg/pr49070.mm: New test. * objc.dg/unnamed-parms.m: New test. --- gcc/cp/parser.c | 8 +++++++- gcc/cp/parser.h | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0a7d18a..d4e4859 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -572,6 +572,8 @@ cp_debug_parser (FILE *file, cp_parser *parser) parser->colon_corrects_to_scope_p); cp_debug_print_flag (file, "Colon doesn't start a class definition", parser->colon_doesnt_start_class_def_p); + cp_debug_print_flag (file, "Parsing an Objective-C++ message context", + parser->objective_c_message_context_p); if (parser->type_definition_forbidden_message) fprintf (file, "Error message for forbidden type definitions: %s %s\n", parser->type_definition_forbidden_message, @@ -6626,7 +6628,9 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, if (token->type == CPP_COLON && parser->colon_corrects_to_scope_p - && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_NAME) + && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_NAME + /* name:name is a valid sequence in an Objective C message. */ + && !parser->objective_c_message_context_p) { gcc_rich_location richloc (token->location); richloc.add_fixit_replace ("::"); @@ -33034,6 +33038,7 @@ cp_parser_objc_message_expression (cp_parser* parser) { tree receiver, messageargs; + parser->objective_c_message_context_p = true; location_t start_loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Eat '['. */ receiver = cp_parser_objc_message_receiver (parser); @@ -33050,6 +33055,7 @@ cp_parser_objc_message_expression (cp_parser* parser) location_t combined_loc = make_location (start_loc, start_loc, end_loc); protected_set_expr_location (result, combined_loc); + parser->objective_c_message_context_p = false; return result; } diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index d587cf2..a468b69 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -350,6 +350,10 @@ struct GTY(()) cp_parser { is terminated by colon. */ bool colon_doesnt_start_class_def_p; + /* TRUE if we are parsing an objective c message, and ':' is permitted + to terminate an assignment-expression. */ + bool objective_c_message_context_p; + /* If non-NULL, then we are parsing a construct where new type definitions are not permitted. The string stored here will be issued as an error message if a type is defined. */ -- cgit v1.1 From c5e55673b486533c4d6d19ac903460f70b48f11a Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 17 Mar 2021 19:39:10 -0400 Subject: c++: Add assert to tsubst. As discussed in the r11-7709 patch, we can now make sure that tsubst never sees a FLOAT_EXPR, much like its counterpart FIX_TRUNC_EXPR. gcc/cp/ChangeLog: * pt.c (tsubst_copy_and_build): Add assert. --- gcc/cp/pt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5e485f1..ea530ef 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -19770,6 +19770,8 @@ tsubst_copy_and_build (tree t, complain|decltype_flag)); case FIX_TRUNC_EXPR: + case FLOAT_EXPR: + /* convert_like should have created an IMPLICIT_CONV_EXPR. */ gcc_unreachable (); case ADDR_EXPR: -- cgit v1.1 From 96ccb325432822f0f5b22bb44c2035ec1e7e8631 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 18 Mar 2021 17:19:17 -0400 Subject: c++: Remove FLOAT_EXPR assert in tsubst. This assert triggered when pr85013.C was compiled with -fchecking=2 which the usual testing doesn't exercise. Let's remove it for now and revisit in GCC 12. gcc/cp/ChangeLog: * pt.c (tsubst_copy_and_build) : Remove. --- gcc/cp/pt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ea530ef..933dfc3 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -19770,7 +19770,6 @@ tsubst_copy_and_build (tree t, complain|decltype_flag)); case FIX_TRUNC_EXPR: - case FLOAT_EXPR: /* convert_like should have created an IMPLICIT_CONV_EXPR. */ gcc_unreachable (); -- cgit v1.1 From bd9b262fa9243e08fefa4973f08d1f09f6694ba0 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 9 Mar 2021 20:55:14 -0500 Subject: c++: Fix error-recovery with requires expression [PR99500] This fixes an ICE on invalid code where one of the parameters was error_mark_node and thus resetting its DECL_CONTEXT crashed. gcc/cp/ChangeLog: PR c++/99500 * parser.c (cp_parser_requirement_parameter_list): Handle error_mark_node. gcc/testsuite/ChangeLog: PR c++/99500 * g++.dg/cpp2a/concepts-err3.C: New test. --- gcc/cp/parser.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d4e4859..ced4bd5 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -28839,8 +28839,11 @@ cp_parser_requirement_parameter_list (cp_parser *parser) if (parm == void_list_node || parm == explicit_void_list_node) break; tree decl = TREE_VALUE (parm); - DECL_CONTEXT (decl) = NULL_TREE; - CONSTRAINT_VAR_P (decl) = true; + if (decl != error_mark_node) + { + DECL_CONTEXT (decl) = NULL_TREE; + CONSTRAINT_VAR_P (decl) = true; + } } return parms; -- cgit v1.1 From 287e3e8466f44f9d395a2e4dcfcda56cc34ceb1c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 19 Mar 2021 00:16:26 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f2f7f45..c63223d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,36 @@ +2021-03-19 Marek Polacek + + PR c++/99500 + * parser.c (cp_parser_requirement_parameter_list): Handle + error_mark_node. + +2021-03-18 Marek Polacek + + * pt.c (tsubst_copy_and_build) : Remove. + +2021-03-18 Marek Polacek + + * pt.c (tsubst_copy_and_build): Add assert. + +2021-03-18 Iain Sandoe + + PR objc++/49070 + * parser.c (cp_debug_parser): Add Objective-C++ message + state flag. + (cp_parser_nested_name_specifier_opt): Allow colon to + terminate an assignment-expression when parsing Objective- + C++ messages. + (cp_parser_objc_message_expression): Set and clear message + parsing state on entry and exit. + * parser.h (struct cp_parser): Add a context flag for + Objective-C++ message state. + +2021-03-18 Martin Liska + + PR c++/99617 + * coroutines.cc (struct var_nest_node): Init then_cl and else_cl + to NULL. + 2021-03-17 Marek Polacek PR c++/97973 -- cgit v1.1 From 82bb66730bc42b8694fdebef607ea6e49e8496bf Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 19 Mar 2021 18:36:56 +0100 Subject: c++: Only reject reinterpret casts from pointers to integers for manifestly_const_eval evaluation [PR99456] My PR82304/PR95307 fix moved reinterpret cast from pointer to integer diagnostics from cxx_eval_outermost_constant_expr where it caught invalid code only at the outermost level down into cxx_eval_constant_expression. Unfortunately, it regressed following testcase, we emit worse code including dynamic initialization of some vars. While the initializers are not constant expressions due to the reinterpret_cast in there, there is no reason not to fold them as an optimization. I've tried to make this dependent on !ctx->quiet, but that regressed two further tests, and on ctx->strict, which regressed other tests, so this patch bases that on manifestly_const_eval. The new testcase is now optimized as much as it used to be in GCC 10 and the only regression it causes is an extra -Wnarrowing warning on vla22.C test on invalid code (which the patch adjusts). 2021-03-19 Jakub Jelinek PR c++/99456 * constexpr.c (cxx_eval_constant_expression): For CONVERT_EXPR from INDIRECT_TYPE_P to ARITHMETIC_TYPE_P, when !ctx->manifestly_const_eval don't diagnose it, set *non_constant_p nor return t. * g++.dg/opt/pr99456.C: New test. * g++.dg/ext/vla22.C: Expect a -Wnarrowing warning for c++11 and later. --- gcc/cp/constexpr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index c946744..42d00ec 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -6656,7 +6656,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (TREE_CODE (t) == CONVERT_EXPR && ARITHMETIC_TYPE_P (type) - && INDIRECT_TYPE_P (TREE_TYPE (op))) + && INDIRECT_TYPE_P (TREE_TYPE (op)) + && ctx->manifestly_const_eval) { if (!ctx->quiet) error_at (loc, -- cgit v1.1 From 5f256a70a05fcfc5a1caf56678ceb12b4f87f781 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 20 Mar 2021 00:16:24 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c63223d..ec300503 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2021-03-19 Jakub Jelinek + + PR c++/99456 + * constexpr.c (cxx_eval_constant_expression): For CONVERT_EXPR from + INDIRECT_TYPE_P to ARITHMETIC_TYPE_P, when !ctx->manifestly_const_eval + don't diagnose it, set *non_constant_p nor return t. + 2021-03-19 Marek Polacek PR c++/99500 -- cgit v1.1 From 9f59cb7cac009f3c6eba81eb09714699b9ac9f8d Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 20 Mar 2021 17:02:06 +0100 Subject: c-family: Fix PR94272 -fcompare-debug issue even for C [PR99230] The following testcase results in -fcompare-debug failure. The problem is the similar like in PR94272 https://gcc.gnu.org/pipermail/gcc-patches/2020-March/542562.html When genericizing, with -g0 we have just a TREE_SIDE_EFFECTS DO_STMT in a branch of if, while with -g we have that wrapped into TREE_SIDE_EFFECTS STATEMENT_LIST containing DEBUG_BEGIN_STMT and that DO_STMT. The do loop is empty with 0 condition, so c_genericize_control_stmt turns it into an empty statement (without TREE_SIDE_EFFECTS). For -g0 that means that suddenly the if branch doesn't have side effects and is expanded differently. But with -g we still have TREE_SIDE_EFFECTS STATEMENT_LIST containing DEBUG_BEGIN_STMT and non-TREE_SIDE_EFFECTS stmt. The following patch fixes that by detecting this case and removing TREE_SIDE_EFFECTS. And, so that we don't duplicate the same code, changes the C++ FE to just call the c_genericize_control_stmt function that can now handle it. 2021-03-20 Jakub Jelinek PR debug/99230 * c-gimplify.c (c_genericize_control_stmt): Handle STATEMENT_LIST. * cp-gimplify.c (cp_genericize_r) : Remove special code, instead call c_genericize_control_stmt. * gcc.dg/pr99230.c: New test. --- gcc/cp/cp-gimplify.c | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index df89ff3..4baa336 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -1464,35 +1464,6 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) walk_subtrees = 0; break; - case STATEMENT_LIST: - if (TREE_SIDE_EFFECTS (stmt)) - { - tree_stmt_iterator i; - int nondebug_stmts = 0; - bool clear_side_effects = true; - /* Genericization can clear TREE_SIDE_EFFECTS, e.g. when - transforming an IF_STMT into COND_EXPR. If such stmt - appears in a STATEMENT_LIST that contains only that - stmt and some DEBUG_BEGIN_STMTs, without -g where the - STATEMENT_LIST wouldn't be present at all the resulting - expression wouldn't have TREE_SIDE_EFFECTS set, so make sure - to clear it even on the STATEMENT_LIST in such cases. */ - for (i = tsi_start (stmt); !tsi_end_p (i); tsi_next (&i)) - { - tree t = tsi_stmt (i); - if (TREE_CODE (t) != DEBUG_BEGIN_STMT && nondebug_stmts < 2) - nondebug_stmts++; - cp_walk_tree (tsi_stmt_ptr (i), cp_genericize_r, data, NULL); - if (TREE_CODE (t) != DEBUG_BEGIN_STMT - && (nondebug_stmts > 1 || TREE_SIDE_EFFECTS (tsi_stmt (i)))) - clear_side_effects = false; - } - if (clear_side_effects) - TREE_SIDE_EFFECTS (stmt) = 0; - *walk_subtrees = 0; - } - break; - case OMP_DISTRIBUTE: /* Need to explicitly instantiate copy ctors on class iterators of composite distribute parallel for. */ @@ -1566,6 +1537,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) case OMP_SIMD: case OMP_LOOP: case OACC_LOOP: + case STATEMENT_LIST: /* These cases are handled by shared code. */ c_genericize_control_stmt (stmt_p, walk_subtrees, data, cp_genericize_r, cp_walk_subtrees); -- cgit v1.1 From 6af7b307f659a4f1845a9efd36ca37899515e234 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 21 Mar 2021 00:16:22 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ec300503..b6cf315 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2021-03-20 Jakub Jelinek + + PR debug/99230 + * cp-gimplify.c (cp_genericize_r) : Remove + special code, instead call c_genericize_control_stmt. + 2021-03-19 Jakub Jelinek PR c++/99456 -- cgit v1.1 From c4519fe3db366d781f342b7f04c4a09e4cc9fbd9 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Sat, 20 Mar 2021 20:57:13 +0100 Subject: C++ modules: fix alloc-dealloc-mismatch ASAN issue gcc/cp/ChangeLog: PR c++/99687 * module.cc (fini_modules): Call vec_free instead of delete. --- gcc/cp/module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 6dbdc92..551cb66 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -20009,7 +20009,7 @@ fini_modules () modules_hash = NULL; /* Or entity array. We still need the entity map to find import numbers. */ - delete entity_ary; + vec_free (entity_ary); entity_ary = NULL; /* Or remember any pending entities. */ -- cgit v1.1 From 87e3c2ef682e2ba7692ee56142a4eb5b6441c4d3 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 18 Mar 2021 05:12:59 -0700 Subject: c++: duplicate alias templates with decltype [PR 99425] This failure was ultimately from incorrect handling of alias templates, but required a specific set of occurrences to happen in the specialization hash table. This cleans up the specialization streaming to add alias instantiations at the same point as other instantiations. I also removed some unneeded global variables dealing with mapping of duplicate decl contexts. PR c++/99425 gcc/cp/ * cp-tree.h (map_context_from, map_context_to): Delete. (add_mergeable_specialization): Add is_alias parm. * pt.c (add_mergeable_specialization): Add is_alias parm, add them. * module.cc (map_context_from, map_context_to): Delete. (trees_in::decl_value): Add specializations later, adjust call. Drop useless alias lookup. Set duplicate fn parm context. (check_mergeable_decl): Drop context mapping. (trees_in::is_matching_decl): Likewise. (trees_in::read_function_def): Drop parameter context adjustment here. gcc/testsuite/ * g++.dg/modules/pr99425-1.h: New. * g++.dg/modules/pr99425-1_a.H: New. * g++.dg/modules/pr99425-1_b.H: New. * g++.dg/modules/pr99425-1_c.C: New. * g++.dg/modules/pr99425-2_a.X: New. * g++.dg/modules/pr99425-2_b.X: New. * g++.dg/template/pr99425.C: New. --- gcc/cp/cp-tree.h | 7 ++--- gcc/cp/module.cc | 82 ++++++++++++++++++++------------------------------------ gcc/cp/pt.c | 38 ++++++++++++++++++-------- 3 files changed, 58 insertions(+), 69 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 81ff375..e68e390 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5444,10 +5444,6 @@ extern int comparing_specializations; FIXME we should always do this except during deduction/ordering. */ extern int comparing_dependent_aliases; -/* When comparing specializations permit context _FROM to match _TO. */ -extern tree map_context_from; -extern tree map_context_to; - /* In parser.c. */ /* Nonzero if we are parsing an unevaluated operand: an operand to @@ -7241,7 +7237,8 @@ extern void walk_specializations (bool, void *); extern tree match_mergeable_specialization (bool is_decl, spec_entry *); extern unsigned get_mergeable_specialization_flags (tree tmpl, tree spec); -extern void add_mergeable_specialization (bool is_decl, spec_entry *, +extern void add_mergeable_specialization (bool is_decl, bool is_alias, + spec_entry *, tree outer, unsigned); extern tree add_outermost_template_args (tree, tree); extern tree add_extra_args (tree, tree); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 551cb66..ad3b7d5 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -279,11 +279,6 @@ static inline tree identifier (const cpp_hashnode *node) return HT_IDENT_TO_GCC_IDENT (HT_NODE (const_cast (node))); } -/* During duplicate detection we need to tell some comparators that - these are equivalent. */ -tree map_context_from; -tree map_context_to; - /* Id for dumping module information. */ int module_dump_id; @@ -8074,16 +8069,6 @@ trees_in::decl_value () if (spec.spec) set_constraints (decl, spec.spec); - if (mk & MK_template_mask - || mk == MK_partial) - { - /* Add to specialization tables now that constraints etc are - added. */ - bool is_type = mk == MK_partial || !(mk & MK_tmpl_decl_mask); - - spec.spec = is_type ? type : mk & MK_tmpl_tmpl_mask ? inner : decl; - add_mergeable_specialization (!is_type, &spec, decl, spec_flags); - } if (TREE_CODE (decl) == INTEGER_CST && !TREE_OVERFLOW (decl)) { @@ -8111,28 +8096,25 @@ trees_in::decl_value () /* Set the TEMPLATE_DECL's type. */ TREE_TYPE (decl) = TREE_TYPE (inner); + if (mk & MK_template_mask + || mk == MK_partial) + { + /* Add to specialization tables now that constraints etc are + added. */ + bool is_type = mk == MK_partial || !(mk & MK_tmpl_decl_mask); + + spec.spec = is_type ? type : mk & MK_tmpl_tmpl_mask ? inner : decl; + add_mergeable_specialization (!is_type, + !is_type && mk & MK_tmpl_alias_mask, + &spec, decl, spec_flags); + } + if (NAMESPACE_SCOPE_P (decl) && (mk == MK_named || mk == MK_unique || mk == MK_enum || mk == MK_friend_spec) && !(VAR_OR_FUNCTION_DECL_P (decl) && DECL_LOCAL_DECL_P (decl))) add_module_namespace_decl (CP_DECL_CONTEXT (decl), decl); - /* The late insertion of an alias here or an implicit member - (next block), is ok, because we ensured that all imports were - loaded up before we started this cluster. Thus an insertion - from some other import cannot have happened between the - merged insertion above and these insertions down here. */ - if (mk == MK_alias_spec) - { - /* Insert into type table. */ - tree ti = DECL_TEMPLATE_INFO (inner); - spec_entry elt = - {TI_TEMPLATE (ti), TI_ARGS (ti), TREE_TYPE (inner)}; - tree texist = match_mergeable_specialization (false, &elt); - if (texist) - set_overrun (); - } - if (DECL_ARTIFICIAL (decl) && TREE_CODE (decl) == FUNCTION_DECL && !DECL_TEMPLATE_INFO (decl) @@ -8176,6 +8158,14 @@ trees_in::decl_value () if (!is_matching_decl (existing, decl, is_typedef)) unmatched_duplicate (existing); + if (inner && TREE_CODE (inner) == FUNCTION_DECL) + { + tree e_inner = STRIP_TEMPLATE (existing); + for (auto parm = DECL_ARGUMENTS (inner); + parm; parm = DECL_CHAIN (parm)) + DECL_CONTEXT (parm) = e_inner; + } + /* And our result is the existing node. */ decl = existing; } @@ -8186,7 +8176,7 @@ trees_in::decl_value () if (!e) { spec.spec = inner; - add_mergeable_specialization (true, &spec, decl, spec_flags); + add_mergeable_specialization (true, false, &spec, decl, spec_flags); } else if (e != existing) set_overrun (); @@ -10378,8 +10368,9 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, { if (mk & MK_tmpl_alias_mask) /* It should be in both tables. */ - gcc_assert (match_mergeable_specialization (false, entry) - == TREE_TYPE (existing)); + gcc_checking_assert + (match_mergeable_specialization (false, entry) + == TREE_TYPE (existing)); else if (mk & MK_tmpl_tmpl_mask) existing = DECL_TI_TEMPLATE (existing); } @@ -10392,7 +10383,7 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, } /* The walkabout should have found ourselves. */ - gcc_assert (existing == decl); + gcc_checking_assert (existing == decl); } } else if (mk != MK_unique) @@ -10622,8 +10613,6 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key) break; case FUNCTION_DECL: - map_context_from = d_inner; - map_context_to = m_inner; if (tree m_type = TREE_TYPE (m_inner)) if ((!key.ret || same_type_p (key.ret, fndecl_declared_return_type (m_inner))) @@ -10647,7 +10636,6 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key) if (cp_tree_equal (key.constraints, m_reqs)) found = match; } - map_context_from = map_context_to = NULL_TREE; break; case TYPE_DECL: @@ -11022,12 +11010,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) gcc_checking_assert (TREE_CODE (e_inner) == TREE_CODE (d_inner)); } - gcc_checking_assert (!map_context_from); - /* This mapping requres the new decl on the lhs and the existing - entity on the rhs of the comparitors below. */ - map_context_from = d_inner; - map_context_to = e_inner; - if (TREE_CODE (d_inner) == FUNCTION_DECL) { tree e_ret = fndecl_declared_return_type (existing); @@ -11104,7 +11086,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) else if (!cp_tree_equal (TREE_TYPE (decl), TREE_TYPE (existing))) { mismatch: - map_context_from = map_context_to = NULL_TREE; if (DECL_IS_UNDECLARED_BUILTIN (existing)) /* Just like duplicate_decls, presum the user knows what they're doing in overriding a builtin. */ @@ -11121,8 +11102,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) } } - map_context_from = map_context_to = NULL_TREE; - if (DECL_IS_UNDECLARED_BUILTIN (existing) && !DECL_IS_UNDECLARED_BUILTIN (decl)) { @@ -11463,10 +11442,6 @@ trees_in::read_function_def (tree decl, tree maybe_template) tree maybe_dup = odr_duplicate (maybe_template, DECL_SAVED_TREE (decl)); bool installing = maybe_dup && !DECL_SAVED_TREE (decl); - if (maybe_dup) - for (auto parm = DECL_ARGUMENTS (maybe_dup); parm; parm = DECL_CHAIN (parm)) - DECL_CONTEXT (parm) = decl; - if (int wtag = i ()) { int tag = 1; @@ -12881,10 +12856,11 @@ specialization_add (bool decl_p, spec_entry *entry, void *data_) || DECL_CLASS_TEMPLATE_P (entry->tmpl)); /* Only alias templates can appear in both tables (and - if they're in the type table they must also be in the decl table). */ + if they're in the type table they must also be in the decl + table). */ gcc_checking_assert (!match_mergeable_specialization (true, entry) - == (decl_p || !DECL_ALIAS_TEMPLATE_P (entry->tmpl))); + == !DECL_ALIAS_TEMPLATE_P (entry->tmpl)); } else if (VAR_OR_FUNCTION_DECL_P (entry->spec)) gcc_checking_assert (!DECL_LOCAL_DECL_P (entry->spec)); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 933dfc3..2736bb4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -30009,25 +30009,41 @@ get_mergeable_specialization_flags (tree tmpl, tree decl) get_mergeable_specialization_flags. */ void -add_mergeable_specialization (bool decl_p, spec_entry *elt, +add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt, tree decl, unsigned flags) { - hash_table *specializations - = decl_p ? decl_specializations : type_specializations; - hashval_t hash = spec_hasher::hash (elt); - auto *slot = specializations->find_slot_with_hash (elt, hash, INSERT); - - /* We don't distinguish different constrained partial type - specializations, so there could be duplicates. Everything else - must be new. */ - if (!(flags & 2 && *slot)) + if (decl_p) { - gcc_checking_assert (!*slot); + auto *slot = decl_specializations->find_slot_with_hash (elt, hash, INSERT); + gcc_checking_assert (!*slot); auto entry = ggc_alloc (); *entry = *elt; *slot = entry; + + if (alias_p) + { + elt->spec = TREE_TYPE (elt->spec); + gcc_checking_assert (elt->spec); + } + } + + if (!decl_p || alias_p) + { + auto *slot = type_specializations->find_slot_with_hash (elt, hash, INSERT); + + /* We don't distinguish different constrained partial type + specializations, so there could be duplicates. Everything else + must be new. */ + if (!(flags & 2 && *slot)) + { + gcc_checking_assert (!*slot); + + auto entry = ggc_alloc (); + *entry = *elt; + *slot = entry; + } } if (flags & 1) -- cgit v1.1 From 2bfd081f1bce3fb7f791591e741723dce4e884ed Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 22 Mar 2021 12:35:35 -0700 Subject: c++: Cross-module partial specialiations [PR 99480] We were not correctly handling cross-module redeclarations of partial-specializations. They have their own TEMPLATE_DECL, which we need to locate. I had a FIXME there about this case. Guess it's fixed now. PR c++/99480 gcc/cp/ * module.cc (depset::hash::make_dependency): Propagate flags for partial specialization. (module_may_redeclare): Handle partial specialization. gcc/testsuite/ * g++.dg/modules/pr99480_a.H: New. * g++.dg/modules/pr99480_b.H: New. --- gcc/cp/module.cc | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index ad3b7d5..e4da555 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -12444,6 +12444,11 @@ depset::hash::make_dependency (tree decl, entity_kind ek) *slot = redirect; + if (DECL_LANG_SPECIFIC (decl)) + { + DECL_MODULE_IMPORT_P (partial) = DECL_MODULE_IMPORT_P (decl); + DECL_MODULE_PURVIEW_P (partial) = DECL_MODULE_PURVIEW_P (decl); + } depset *tmpl_dep = make_dependency (partial, EK_PARTIAL); gcc_checking_assert (tmpl_dep->get_entity_kind () == EK_PARTIAL); @@ -18429,13 +18434,20 @@ module_may_redeclare (tree decl) if (tree ti = node_template_info (decl, use_tpl)) { tree tmpl = TI_TEMPLATE (ti); - if (DECL_TEMPLATE_RESULT (tmpl) == decl) + if (use_tpl == 2) + { + /* A partial specialization. Find that specialization's + template_decl. */ + for (tree list = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); + list; list = TREE_CHAIN (list)) + if (DECL_TEMPLATE_RESULT (TREE_VALUE (list)) == decl) + { + decl = TREE_VALUE (list); + break; + } + } + else if (DECL_TEMPLATE_RESULT (tmpl) == decl) decl = tmpl; - // FIXME: What about partial specializations? We need to - // look at the specialization list in that case. Unless our - // caller's given us the right thing. An alternative would - // be to put both the template and the result into the - // entity hash, but that seems expensive? } unsigned index = import_entity_index (decl); them = import_entity_module (index); -- cgit v1.1 From 8b744f46a2426b6656e52ace697a569795c9153a Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 23 Mar 2021 00:16:25 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b6cf315..fb2978e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,29 @@ +2021-03-22 Nathan Sidwell + + PR c++/99480 + * module.cc (depset::hash::make_dependency): Propagate flags for + partial specialization. + (module_may_redeclare): Handle partial specialization. + +2021-03-22 Nathan Sidwell + + PR c++/99425 + * cp-tree.h (map_context_from, map_context_to): Delete. + (add_mergeable_specialization): Add is_alias parm. + * pt.c (add_mergeable_specialization): Add is_alias parm, add them. + * module.cc (map_context_from, map_context_to): Delete. + (trees_in::decl_value): Add specializations later, adjust call. + Drop useless alias lookup. Set duplicate fn parm context. + (check_mergeable_decl): Drop context mapping. + (trees_in::is_matching_decl): Likewise. + (trees_in::read_function_def): Drop parameter context adjustment + here. + +2021-03-22 Martin Liska + + PR c++/99687 + * module.cc (fini_modules): Call vec_free instead of delete. + 2021-03-20 Jakub Jelinek PR debug/99230 -- cgit v1.1 From 3e07e7a6a7f34f0ec2f1a3e50ebc52b77de11a30 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 23 Mar 2021 10:23:42 +0100 Subject: c++: Diagnose references to void in structured bindings [PR99650] We ICE on the following testcase, because std::tuple_element<...,...>::type is void and for structured bindings we therefore need to create void & or void && which is invalid. We created such REFERENCE_TYPE and later ICEd in the middle-end. The following patch fixes it by diagnosing that. 2021-03-23 Jakub Jelinek PR c++/99650 * decl.c (cp_finish_decomp): Diagnose void initializers when using tuple_element and get. * g++.dg/cpp1z/decomp55.C: New test. --- gcc/cp/decl.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 8e8f37d..b1d8e44 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -8629,6 +8629,12 @@ cp_finish_decomp (tree decl, tree first, unsigned int count) : get_tuple_element_type (type, i)); input_location = sloc; + if (VOID_TYPE_P (eltype)) + { + error ("%::type%> is %", + i, type); + eltype = error_mark_node; + } if (init == error_mark_node || eltype == error_mark_node) { inform (dloc, "in initialization of structured binding " -- cgit v1.1 From 6acd6692f1ac3c2ece3da36178df73e3b12c4f65 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Tue, 23 Mar 2021 05:18:04 -0700 Subject: c++: Over-zealous assert [PR 99239] This was simply an overzealous assert. Possibly correct thinking at the time that code was written, but not true now. Of course we can have imported artificial decls. PR c++/99239 gcc/cp/ * decl.c (duplicate_decls): Remove assert about maybe-imported artificial decls. gcc/testsuite/ * g++.dg/modules/pr99239_a.H: New. * g++.dg/modules/pr99239_b.H: New. --- gcc/cp/decl.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b1d8e44..3483b0c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2041,8 +2041,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) { if (DECL_ARTIFICIAL (olddecl)) { - gcc_checking_assert (!(DECL_LANG_SPECIFIC (olddecl) - && DECL_MODULE_IMPORT_P (olddecl))); if (!(global_purview_p () || not_module_p ())) error ("declaration %qD conflicts with builtin", newdecl); else -- cgit v1.1 From 831f9f768eb1fbf9a31d9a89591188b1487b6376 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 9 Mar 2021 19:23:48 -0500 Subject: c++: Fix bogus warning in deprecated namespace [PR99318] In GCC 10, I introduced cp_warn_deprecated_use_scopes so that we can handle attribute deprecated on a namespace declaration. This function walks the decl's contexts so that we warn for code like namespace [[deprecated]] N { struct S { }; } N::S s; We call cp_warn_deprecated_use_scopes when we encounter a TYPE_DECL. But in the following testcase we have a TYPE_DECL whose context is a deprecated function; that itself is not a reason to warn. This patch limits for which entities we call cp_warn_deprecated_use; essentially it's what can follow ::. I noticed that we didn't test that struct [[deprecated]] S { static void fn(); }; S::fn(); produces the expected warning, so I've added gen-attrs-73.C. gcc/cp/ChangeLog: PR c++/99318 * decl2.c (cp_warn_deprecated_use_scopes): Only call cp_warn_deprecated_use when decl is a namespace, class, or enum. gcc/testsuite/ChangeLog: PR c++/99318 * g++.dg/cpp0x/attributes-namespace6.C: New test. * g++.dg/cpp0x/gen-attrs-73.C: New test. --- gcc/cp/decl2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index c46100d..ef79f6c 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -5529,7 +5529,8 @@ cp_warn_deprecated_use_scopes (tree scope) && scope != error_mark_node && scope != global_namespace) { - if (cp_warn_deprecated_use (scope)) + if ((TREE_CODE (scope) == NAMESPACE_DECL || OVERLOAD_TYPE_P (scope)) + && cp_warn_deprecated_use (scope)) return; if (TYPE_P (scope)) scope = CP_TYPE_CONTEXT (scope); -- cgit v1.1 From bd71889b9017751e1a06970d20b28b9fe9479bdc Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Tue, 23 Mar 2021 12:23:30 -0700 Subject: c++: Note duplicates in symbol table [PR 99283] I ran into this reducing 99283, we were failing to mark binding vectors when the current TU declares a duplicate decl (as opposed to an import introduces a duplicate). PR c++/99283 gcc/cp/ * name-lookup.c (check_module_override): Set global or partition DUP on the binding vector. gcc/testsuite/ * g++.dg/modules/pr99283-1_a.H: New. * g++.dg/modules/pr99283-1_b.H: New. --- gcc/cp/name-lookup.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index a6257f5..f4263f1 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3528,6 +3528,7 @@ static tree check_module_override (tree decl, tree mvec, bool hiding, tree scope, tree name) { + tree match = NULL_TREE; bitmap imports = get_import_bitmap (); binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (mvec); unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (mvec); @@ -3566,13 +3567,15 @@ check_module_override (tree decl, tree mvec, bool hiding, bind = STAT_VISIBLE (bind); for (ovl_iterator iter (bind); iter; ++iter) - if (iter.using_p ()) - ; - else if (tree match = duplicate_decls (decl, *iter, hiding)) - return match; + if (!iter.using_p ()) + { + match = duplicate_decls (decl, *iter, hiding); + if (match) + goto matched; + } } - if (TREE_PUBLIC (scope) && TREE_PUBLIC (decl) && !not_module_p () + if (TREE_PUBLIC (scope) && TREE_PUBLIC (STRIP_TEMPLATE (decl)) /* Namespaces are dealt with specially in make_namespace_finish. */ && !(TREE_CODE (decl) == NAMESPACE_DECL && !DECL_NAMESPACE_ALIAS (decl))) @@ -3588,14 +3591,26 @@ check_module_override (tree decl, tree mvec, bool hiding, for (ovl_iterator iter (mergeable); iter; ++iter) { - tree match = *iter; - - if (duplicate_decls (decl, match, hiding)) - return match; + match = duplicate_decls (decl, *iter, hiding); + if (match) + goto matched; } } return NULL_TREE; + + matched: + if (match != error_mark_node) + { + if (named_module_p ()) + BINDING_VECTOR_PARTITION_DUPS_P (mvec) = true; + else + BINDING_VECTOR_GLOBAL_DUPS_P (mvec) = true; + } + + return match; + + } /* Record DECL as belonging to the current lexical scope. Check for -- cgit v1.1 From bf1f3168f474734400e7a97660d1e7dec664bca9 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 24 Mar 2021 00:16:25 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fb2978e..8133098 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,27 @@ +2021-03-23 Nathan Sidwell + + PR c++/99283 + * name-lookup.c (check_module_override): Set global or partition + DUP on the binding vector. + +2021-03-23 Marek Polacek + + PR c++/99318 + * decl2.c (cp_warn_deprecated_use_scopes): Only call + cp_warn_deprecated_use when decl is a namespace, class, or enum. + +2021-03-23 Nathan Sidwell + + PR c++/99239 + * decl.c (duplicate_decls): Remove assert about maybe-imported + artificial decls. + +2021-03-23 Jakub Jelinek + + PR c++/99650 + * decl.c (cp_finish_decomp): Diagnose void initializers when + using tuple_element and get. + 2021-03-22 Nathan Sidwell PR c++/99480 -- cgit v1.1 From 660eb7e9dee46ef1c986d5a4fa5cbd182b435518 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 25 Mar 2021 11:33:35 +0100 Subject: c-family: Fix up -Wduplicated-branches for union members [PR99565] Honza has fairly recently changed operand_equal_p to compare DECL_FIELD_OFFSET for COMPONENT_REFs when comparing addresses. As the first testcase in this patch shows, while that is very nice for optimizations, for the -Wduplicated-branches warning it causes regressions. Pedantically a union in both C and C++ has only one active member at a time, so using some other union member even if it has the same type is UB, so I think the warning shouldn't warn when it sees access to different fields that happen to have the same offset and should consider them different. In my first attempt to fix this I've keyed the old behavior on OEP_LEXICOGRAPHIC, but unfortunately that has various problems, the warning has a quick non-lexicographic compare in build_conditional_expr* and another lexicographic more expensive one later during genericization and turning the first one into lexicographic would mean wasting compile time on large conditionals. So, this patch instead introduces a new OEP_ flag and makes sure to pass it to operand_equal_p in all -Wduplicated-branches cases. The cvt.c changes are because on the other testcase we were warning with UNKNOWN_LOCATION, so the user wouldn't really know where the questionable code is. 2021-03-25 Jakub Jelinek PR c++/99565 * tree-core.h (enum operand_equal_flag): Add OEP_ADDRESS_OF_SAME_FIELD. * fold-const.c (operand_compare::operand_equal_p): Don't compare field offsets if OEP_ADDRESS_OF_SAME_FIELD. * c-warn.c (do_warn_duplicated_branches): Pass also OEP_ADDRESS_OF_SAME_FIELD to operand_equal_p. * c-typeck.c (build_conditional_expr): Pass OEP_ADDRESS_OF_SAME_FIELD to operand_equal_p. * call.c (build_conditional_expr_1): Pass OEP_ADDRESS_OF_SAME_FIELD to operand_equal_p. * cvt.c (convert_to_void): Preserve location_t on COND_EXPR or or COMPOUND_EXPR. * g++.dg/warn/Wduplicated-branches6.C: New test. * g++.dg/warn/Wduplicated-branches7.C: New test. --- gcc/cp/call.c | 3 ++- gcc/cp/cvt.c | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 390b8aa..bab0c89 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5798,7 +5798,8 @@ build_conditional_expr_1 (const op_location_t &loc, warn here, because the COND_EXPR will be turned into ARG2. */ if (warn_duplicated_branches && (complain & tf_warning) - && (arg2 == arg3 || operand_equal_p (arg2, arg3, 0))) + && (arg2 == arg3 || operand_equal_p (arg2, arg3, + OEP_ADDRESS_OF_SAME_FIELD))) warning_at (EXPR_LOCATION (result), OPT_Wduplicated_branches, "this condition has identical branches"); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 2ea3210..d105113 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -1198,8 +1198,8 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) new_op2 = convert_to_void (op2, ICV_CAST, complain); } - expr = build3 (COND_EXPR, TREE_TYPE (new_op2), - TREE_OPERAND (expr, 0), new_op1, new_op2); + expr = build3_loc (loc, COND_EXPR, TREE_TYPE (new_op2), + TREE_OPERAND (expr, 0), new_op1, new_op2); break; } @@ -1215,8 +1215,8 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) if (new_op1 != op1) { - tree t = build2 (COMPOUND_EXPR, TREE_TYPE (new_op1), - TREE_OPERAND (expr, 0), new_op1); + tree t = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (new_op1), + TREE_OPERAND (expr, 0), new_op1); expr = t; } -- cgit v1.1 From 9efd72d28956eb79c7fca38e3c959733a3bb25bb Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 4 Mar 2021 20:20:40 -0500 Subject: c++: -Wconversion vs value-dependent expressions [PR99331] This PR complains that we issue a -Wconversion warning in template struct X {}; template X foo(); saying "conversion from 'long unsigned int' to 'int' may change value". While it's not technically wrong, I suspect -Wconversion warnings aren't all that useful for value-dependent expressions. So this patch disables them. This is a regression that started with r241425: @@ -7278,7 +7306,7 @@ convert_template_argument (tree parm, val = error_mark_node; } } - else if (!dependent_template_arg_p (orig_arg) + else if (!type_dependent_expression_p (orig_arg) && !uses_template_parms (t)) /* We used to call digest_init here. However, digest_init will report errors, which we don't want when complain Here orig_arg is SIZEOF_EXPR; dependent_template_arg_p (orig_arg) was true, but type_dependent_expression_p (orig_arg) is false so we warn in convert_nontype_argument. gcc/cp/ChangeLog: PR c++/99331 * call.c (build_converted_constant_expr_internal): Don't emit -Wconversion warnings. gcc/testsuite/ChangeLog: PR c++/99331 * g++.dg/warn/Wconversion5.C: New test. --- gcc/cp/call.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index bab0c89..e757e18 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4484,6 +4484,9 @@ build_converted_constant_expr_internal (tree type, tree expr, && processing_template_decl) conv = next_conversion (conv); + /* Issuing conversion warnings for value-dependent expressions is + likely too noisy. */ + warning_sentinel w (warn_conversion); conv->check_narrowing = true; conv->check_narrowing_const_only = true; expr = convert_like (conv, expr, complain); -- cgit v1.1 From 0b86a6438191f720bebf880a2b932cd97d10229a Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 25 Mar 2021 21:06:09 +0100 Subject: c++: Diagnose bare parameter packs in bitfield widths [PR99745] The following invalid tests ICE because we don't diagnose (and drop) bare parameter packs in bitfield widths. 2021-03-25 Jakub Jelinek PR c++/99745 * decl2.c (grokbitfield): Diagnose bitfields containing bare parameter packs and don't set DECL_BIT_FIELD_REPRESENTATIVE in that case. * g++.dg/cpp0x/variadic181.C: New test. --- gcc/cp/decl2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index ef79f6c..a82960f 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1117,7 +1117,7 @@ grokbitfield (const cp_declarator *declarator, && !INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (width))) error ("width of bit-field %qD has non-integral type %qT", value, TREE_TYPE (width)); - else + else if (!check_for_bare_parameter_packs (width)) { /* Temporarily stash the width in DECL_BIT_FIELD_REPRESENTATIVE. check_bitfield_decl picks it from there later and sets DECL_SIZE -- cgit v1.1 From d4e0bdbc036644401f9de49f594b2bb16b287381 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 5 Mar 2021 15:46:50 -0500 Subject: c++: ICE on invalid with inheriting constructors [PR94751] This is an ICE on invalid where we crash because since r269032 we keep error_mark_node around instead of using noexcept_false_spec when things go wrong; see the walk_field_subobs hunk. We crash in deduce_inheriting_ctor which calls synthesized_method_walk to deduce the exception-specification, but fails to do so in this case, because the testcase is invalid so get_nsdmi returns error_mark_node for the member 'c', and per r269032 the error_mark_node propagates back to deduce_inheriting_ctor which subsequently calls build_exception_variant whereon we crash. I think we should return early if the deduction fails and I decided to call mark_used to get an error right away instead of hoping that it would get called later. My worry is that we could forget that there was an error and think that we just deduced noexcept(false). And then I noticed that the test still crashes in C++98. Here again we failed to deduce the exception-specification in implicitly_declare_fn, but nothing reported an error between synthesized_method_walk and the assert. Well, not much we can do except calling synthesized_method_walk again, this time in the verbose mode and making sure that we did get an error. gcc/cp/ChangeLog: PR c++/94751 * call.c (build_over_call): Maybe call mark_used in case deduce_inheriting_ctor fails and return error_mark_node. * cp-tree.h (deduce_inheriting_ctor): Adjust declaration. * method.c (deduce_inheriting_ctor): Return bool if the deduction fails. (implicitly_declare_fn): If raises is error_mark_node, call synthesized_method_walk with diag being true. gcc/testsuite/ChangeLog: PR c++/94751 * g++.dg/cpp0x/inh-ctor37.C: New test. --- gcc/cp/call.c | 9 +++++++-- gcc/cp/cp-tree.h | 2 +- gcc/cp/method.c | 22 +++++++++++++++++----- 3 files changed, 25 insertions(+), 8 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e757e18..4b81d0f 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8947,8 +8947,13 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) /* OK, we're actually calling this inherited constructor; set its deletedness appropriately. We can get away with doing this here because calling is the only way to refer to a constructor. */ - if (DECL_INHERITED_CTOR (fn)) - deduce_inheriting_ctor (fn); + if (DECL_INHERITED_CTOR (fn) + && !deduce_inheriting_ctor (fn)) + { + if (complain & tf_error) + mark_used (fn); + return error_mark_node; + } /* Make =delete work with SFINAE. */ if (DECL_DELETED_FN (fn)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e68e390..f647052 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6915,7 +6915,7 @@ extern bool is_xible (enum tree_code, tree, tree); extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error); extern bool maybe_explain_implicit_delete (tree); extern void explain_implicit_non_constexpr (tree); -extern void deduce_inheriting_ctor (tree); +extern bool deduce_inheriting_ctor (tree); extern bool decl_remember_implicit_trigger_p (tree); extern void synthesize_method (tree); extern tree lazily_declare_fn (special_function_kind, diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 3fe3bd8..25c1e68 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -2789,9 +2789,9 @@ explain_implicit_non_constexpr (tree decl) /* DECL is an instantiation of an inheriting constructor template. Deduce the correct exception-specification and deletedness for this particular - specialization. */ + specialization. Return true if the deduction succeeds; false otherwise. */ -void +bool deduce_inheriting_ctor (tree decl) { decl = DECL_ORIGIN (decl); @@ -2804,6 +2804,8 @@ deduce_inheriting_ctor (tree decl) /*diag*/false, &inh, FUNCTION_FIRST_USER_PARMTYPE (decl)); + if (spec == error_mark_node) + return false; if (TREE_CODE (inherited_ctor_binfo (decl)) != TREE_BINFO) /* Inherited the same constructor from different base subobjects. */ deleted = true; @@ -2818,6 +2820,8 @@ deduce_inheriting_ctor (tree decl) TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone), spec); SET_DECL_INHERITED_CTOR (clone, inh); } + + return true; } /* Implicitly declare the special function indicated by KIND, as a @@ -2993,9 +2997,17 @@ implicitly_declare_fn (special_function_kind kind, tree type, if (raises != error_mark_node) fn_type = build_exception_variant (fn_type, raises); else - /* Can happen, eg, in C++98 mode for an ill-formed non-static data - member initializer (c++/89914). */ - gcc_assert (seen_error ()); + { + /* Can happen, e.g., in C++98 mode for an ill-formed non-static data + member initializer (c++/89914). Also, in C++98, we might have + failed to deduce RAISES, so try again but complain this time. */ + if (cxx_dialect < cxx11) + synthesized_method_walk (type, kind, const_p, nullptr, nullptr, + nullptr, nullptr, /*diag=*/true, + &inherited_ctor, inherited_parms); + /* We should have seen an error at this point. */ + gcc_assert (seen_error ()); + } } fn = build_lang_decl (FUNCTION_DECL, name, fn_type); if (kind != sfk_inheriting_constructor) -- cgit v1.1 From 2132a36370e282d8c0ed0c97e5bfb952e23dbfa1 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 25 Mar 2021 21:35:11 +0100 Subject: c++: Fix source_location inconsistency between calls from templates and non-templates [PR99672] The srcloc19.C testcase shows inconsistency in std::source_location::current() locations between calls from templates and non-templates. The location used by __builtin_source_location comes in both cases from input_location which is set on it by bot_manip when handling the default argument, called during finish_call_expr. The problem is that in templates that input_location comes from the CALL_EXPR we built earlier and that has the combined locus with range between first character of the function name and closing paren with caret on the opening paren, so something printed as caret as: foobar (); ~~~~~~^~ But outside of templates, finish_call_expr is called when input_location is just the closing paren token, i.e. foobar (); ^ and only after that returns we create the combined location and set the CALL_EXPR location to that. So, it means std::source_location::current() reports in templates the column of opening (, while outside of templates closing ). The following patch makes it consistent by creating the combined location already before calling finish_call_expr and temporarily overriding input_location to that. 2021-03-25 Jakub Jelinek PR c++/99672 * parser.c (cp_parser_postfix_expression): For calls, create combined_loc and temporarily set input_location to it before calling finish_call_expr. * g++.dg/concepts/diagnostic2.C: Adjust expected caret line. * g++.dg/cpp1y/builtin_location.C (f4, n6): Move #line directives to match locus changes. * g++.dg/cpp2a/srcloc1.C: Adjust expected column numbers. * g++.dg/cpp2a/srcloc2.C: Likewise. * g++.dg/cpp2a/srcloc15.C: Likewise. * g++.dg/cpp2a/srcloc16.C: Likewise. * g++.dg/cpp2a/srcloc19.C: New test. * g++.dg/modules/adhoc-1_b.C: Adjust expected column numbers and caret line. * g++.dg/modules/macloc-1_c.C: Adjust expected column numbers. * g++.dg/modules/macloc-1_d.C: Likewise. * g++.dg/plugin/diagnostic-test-expressions-1.C: Adjust expected caret line. * testsuite/18_support/source_location/consteval.cc (main): Adjust expected column numbers. * testsuite/18_support/source_location/1.cc (main): Likewise. --- gcc/cp/parser.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ced4bd5..d0477c4 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7564,6 +7564,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, tsubst_flags_t complain = complain_flags (decltype_p); vec *args; location_t close_paren_loc = UNKNOWN_LOCATION; + location_t combined_loc = UNKNOWN_LOCATION; is_member_access = false; @@ -7669,6 +7670,17 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, } } + /* Temporarily set input_location to the combined location + with call expression range, as e.g. build_out_target_exprs + called from convert_default_arg relies on input_location, + so updating it only when the call is fully built results + in inconsistencies between location handling in templates + and outside of templates. */ + if (close_paren_loc != UNKNOWN_LOCATION) + combined_loc = make_location (token->location, start_loc, + close_paren_loc); + iloc_sentinel ils (combined_loc); + if (TREE_CODE (postfix_expression) == COMPONENT_REF) { tree instance = TREE_OPERAND (postfix_expression, 0); @@ -7726,12 +7738,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, complain); if (close_paren_loc != UNKNOWN_LOCATION) - { - location_t combined_loc = make_location (token->location, - start_loc, - close_paren_loc); - postfix_expression.set_location (combined_loc); - } + postfix_expression.set_location (combined_loc); /* The POSTFIX_EXPRESSION is certainly no longer an id. */ idk = CP_ID_KIND_NONE; -- cgit v1.1 From 4493b1c1ad7e2b2a60ad70563b81f51173115471 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 26 Mar 2021 00:16:25 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8133098..ba750a2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,41 @@ +2021-03-25 Jakub Jelinek + + PR c++/99672 + * parser.c (cp_parser_postfix_expression): For calls, create + combined_loc and temporarily set input_location to it before + calling finish_call_expr. + +2021-03-25 Marek Polacek + + PR c++/94751 + * call.c (build_over_call): Maybe call mark_used in case + deduce_inheriting_ctor fails and return error_mark_node. + * cp-tree.h (deduce_inheriting_ctor): Adjust declaration. + * method.c (deduce_inheriting_ctor): Return bool if the deduction + fails. + (implicitly_declare_fn): If raises is error_mark_node, call + synthesized_method_walk with diag being true. + +2021-03-25 Jakub Jelinek + + PR c++/99745 + * decl2.c (grokbitfield): Diagnose bitfields containing bare parameter + packs and don't set DECL_BIT_FIELD_REPRESENTATIVE in that case. + +2021-03-25 Marek Polacek + + PR c++/99331 + * call.c (build_converted_constant_expr_internal): Don't emit + -Wconversion warnings. + +2021-03-25 Jakub Jelinek + + PR c++/99565 + * call.c (build_conditional_expr_1): Pass OEP_ADDRESS_OF_SAME_FIELD + to operand_equal_p. + * cvt.c (convert_to_void): Preserve location_t on COND_EXPR or + or COMPOUND_EXPR. + 2021-03-23 Nathan Sidwell PR c++/99283 -- cgit v1.1 From 6081d8994ed1a0aef6b7f5fb34f091faa3580416 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 26 Mar 2021 09:35:26 +0100 Subject: c++: Fix ICE with nsdmi [PR99705] When adding P0784R7 constexpr new support, we still didn't have P1331R2 implemented and so I had to change also build_vec_delete_1 - instead of having uninitialized tbase temporary later initialized by MODIFY_EXPR I've set the DECL_INITIAL for it - because otherwise it would be rejected during constexpr evaluation which didn't like uninitialized vars. Unfortunately, that change broke the following testcase. The problem is that these temporaries (not just tbase but tbase was the only one with an initializer) are created during NSDMI parsing and current_function_decl is NULL at that point. Later when we clone body of constructors, auto_var_in_fn_p is false for those (as they have NULL DECL_CONTEXT) and so they aren't duplicated, and what is worse, the DECL_INITIAL isn't duplicated either nor processed, and during expansion we ICE because the code from DECL_INITIAL of that var refers to the abstract constructor's PARM_DECL (this) rather than the actual constructor's one. So, either we can just revert those build_vec_delete_1 changes (as done in the second patch - in attachment), or, as the first patch does, we can copy the temporaries during bot_manip like we copy the temporaries of TARGET_EXPRs. To me that looks like a better fix because e.g. if break_out_of_target_exprs is called for the same NSDMI multiple times, sharing the temporaries looks just wrong to me. If the temporaries are declared as BIND_EXPR_VARS of some BIND_EXPR (which is the case of the tbase variable built by build_vec_delete_1 and is the only way how the DECL_INITIAL can be walked by *walk_tree*), then we need to copy it also in the BIND_EXPR BIND_EXPR_VARS chain, other temporaries (those that don't need DECL_INITIAL) often have just DECL_EXPR and no corresponding BIND_EXPR. Note, ({ }) are rejected in nsdmis, so all we run into are temporaries the FE creates artificially. 2021-03-26 Jakub Jelinek PR c++/99705 * tree.c (bot_manip): Remap artificial automatic temporaries mentioned in DECL_EXPR or in BIND_EXPR_VARS. * g++.dg/cpp0x/new5.C: New test. --- gcc/cp/tree.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 3acb643..8c4bd15 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3128,6 +3128,48 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_) } return NULL_TREE; } + if (TREE_CODE (*tp) == DECL_EXPR + && VAR_P (DECL_EXPR_DECL (*tp)) + && DECL_ARTIFICIAL (DECL_EXPR_DECL (*tp)) + && !TREE_STATIC (DECL_EXPR_DECL (*tp))) + { + tree t; + splay_tree_node n + = splay_tree_lookup (target_remap, + (splay_tree_key) DECL_EXPR_DECL (*tp)); + if (n) + t = (tree) n->value; + else + { + t = create_temporary_var (TREE_TYPE (DECL_EXPR_DECL (*tp))); + DECL_INITIAL (t) = DECL_INITIAL (DECL_EXPR_DECL (*tp)); + splay_tree_insert (target_remap, + (splay_tree_key) DECL_EXPR_DECL (*tp), + (splay_tree_value) t); + } + copy_tree_r (tp, walk_subtrees, NULL); + DECL_EXPR_DECL (*tp) = t; + if (data.clear_location && EXPR_HAS_LOCATION (*tp)) + SET_EXPR_LOCATION (*tp, input_location); + return NULL_TREE; + } + if (TREE_CODE (*tp) == BIND_EXPR && BIND_EXPR_VARS (*tp)) + { + copy_tree_r (tp, walk_subtrees, NULL); + for (tree *p = &BIND_EXPR_VARS (*tp); *p; p = &DECL_CHAIN (*p)) + { + gcc_assert (VAR_P (*p) && DECL_ARTIFICIAL (*p) && !TREE_STATIC (*p)); + tree t = create_temporary_var (TREE_TYPE (*p)); + DECL_INITIAL (t) = DECL_INITIAL (*p); + DECL_CHAIN (t) = DECL_CHAIN (*p); + splay_tree_insert (target_remap, (splay_tree_key) *p, + (splay_tree_value) t); + *p = t; + } + if (data.clear_location && EXPR_HAS_LOCATION (*tp)) + SET_EXPR_LOCATION (*tp, input_location); + return NULL_TREE; + } /* Make a copy of this node. */ t = copy_tree_r (tp, walk_subtrees, NULL); -- cgit v1.1 From d82797420c2238e31a7a25fe6db6bd05cd37224d Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Fri, 26 Mar 2021 10:46:31 -0700 Subject: c++: imported templates and alias-template changes [PR 99283] During development of modules, I had difficulty deciding whether the module flags of a template should live on the decl_template_result, the template_decl, or both. I chose the latter, and require them to be consistent. This and a few other defects show how hard that consistency is. Hence this patch move to holding the flags on the template-decl-result decl. That's the entity various bits of the parser have at the appropriate time. Once needs STRIP_TEMPLATE in a bunch of places, which this patch adds. Also a check that we never give a TEMPLATE_DECL to the module flag accessors. This left a problem with how I was handling template aliases. These were in two parts -- separating the TEMPLATE_DECL from the TYPE_DECL. That seemed somewhat funky, but development showed it necessary. Of course, that causes problems if the TEMPLATE_DECL cannot contain 'am imported' information. Investigating now shows that we do not need to treat them separately. By reverting a bit of template instantiation machinery that caused the problem, we're back on course. I think what has happened is that between then and now, other typedef fixes have corrected the underlying problem this separation was working around. It allows a bunch of cleanup in the decl streamer, as we no longer have to handle a null TEMPLATE_DECL_RESULT. PR c++/99283 gcc/cp/ * cp-tree.h (DECL_MODULE_CHECK): Ban TEMPLATE_DECL. (SET_TYPE_TEMPLATE_INFO): Restore Alias template setting. * decl.c (duplicate_decls): Remove template_decl module flag propagation. * module.cc (merge_kind_name): Add alias tmpl spec as a thing. (dumper::impl::nested_name): Adjust for template-decl module flag change. (trees_in::assert_definition): Likewise. (trees_in::install_entity): Likewise. (trees_out::decl_value): Likewise. Remove alias template separation of template and type_decl. (trees_in::decl_value): Likewise. (trees_out::key_mergeable): Likewise, (trees_in::key_mergeable): Likewise. (trees_out::decl_node): Adjust for template-decl module flag change. (depset::hash::make_dependency): Likewise. (get_originating_module, module_may_redeclare): Likewise. (set_instantiating_module, set_defining_module): Likewise. * name-lookup.c (name_lookup::search_adl): Likewise. (do_pushdecl): Likewise. * pt.c (build_template_decl): Likewise. (lookup_template_class_1): Remove special alias_template handling of DECL_TI_TEMPLATE. (tsubst_template_decl): Likewise. gcc/testsuite/ * g++.dg/modules/pr99283-2_a.H: New. * g++.dg/modules/pr99283-2_b.H: New. * g++.dg/modules/pr99283-2_c.H: New. * g++.dg/modules/pr99283-3_a.H: New. * g++.dg/modules/pr99283-3_b.H: New. * g++.dg/modules/pr99283-4.H: New. * g++.dg/modules/tpl-alias-1_a.H: Adjust scans. * g++.dg/modules/tpl-alias-1_b.C: Adjust scans. --- gcc/cp/cp-tree.h | 15 +-- gcc/cp/decl.c | 17 --- gcc/cp/module.cc | 284 ++++++++++++++++++++------------------------------- gcc/cp/name-lookup.c | 6 +- gcc/cp/pt.c | 53 ++-------- 5 files changed, 137 insertions(+), 238 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f647052..9535910 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1661,9 +1661,11 @@ check_constraint_info (tree t) #define CONSTRAINED_PARM_PROTOTYPE(NODE) \ DECL_INITIAL (TYPE_DECL_CHECK (NODE)) -/* Module defines. */ -// Too many _DECLS: FUNCTION,VAR,TYPE,TEMPLATE,CONCEPT or NAMESPACE -#define DECL_MODULE_CHECK(NODE) (NODE) +/* Module flags on FUNCTION,VAR,TYPE,CONCEPT or NAMESPACE + A TEMPLATE_DECL holds them on the DECL_TEMPLATE_RESULT object -- + it's just not practical to keep them consistent. */ +#define DECL_MODULE_CHECK(NODE) \ + TREE_NOT_CHECK (NODE, TEMPLATE_DECL) /* In the purview of a module (including header unit). */ #define DECL_MODULE_PURVIEW_P(N) \ @@ -3626,9 +3628,10 @@ struct GTY(()) lang_decl { /* Set the template information for a non-alias n ENUMERAL_, RECORD_, or UNION_TYPE to VAL. ALIAS's are dealt with separately. */ #define SET_TYPE_TEMPLATE_INFO(NODE, VAL) \ - (gcc_checking_assert (TREE_CODE (NODE) == ENUMERAL_TYPE \ - || (CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE))), \ - (TYPE_LANG_SLOT_1 (NODE) = (VAL))) \ + (TREE_CODE (NODE) == ENUMERAL_TYPE \ + || (CLASS_TYPE_P (NODE) && !TYPE_ALIAS_P (NODE)) \ + ? (TYPE_LANG_SLOT_1 (NODE) = (VAL)) \ + : (DECL_TEMPLATE_INFO (TYPE_NAME (NODE)) = (VAL))) \ #define TI_TEMPLATE(NODE) \ ((struct tree_template_info*)TEMPLATE_INFO_CHECK (NODE))->tmpl diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 3483b0c..6789aa8 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2275,10 +2275,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) } } - DECL_MODULE_IMPORT_P (olddecl) - = DECL_MODULE_IMPORT_P (old_result) - = DECL_MODULE_IMPORT_P (newdecl); - return olddecl; } @@ -2931,19 +2927,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) } } - if (DECL_LANG_SPECIFIC (olddecl) && DECL_TEMPLATE_INFO (olddecl)) - { - /* Repropagate the module information to the template. */ - tree tmpl = DECL_TI_TEMPLATE (olddecl); - - if (DECL_TEMPLATE_RESULT (tmpl) == olddecl) - { - DECL_MODULE_PURVIEW_P (tmpl) = DECL_MODULE_PURVIEW_P (olddecl); - gcc_checking_assert (!DECL_MODULE_IMPORT_P (olddecl)); - DECL_MODULE_IMPORT_P (tmpl) = false; - } - } - if (VAR_OR_FUNCTION_DECL_P (newdecl)) { if (DECL_EXTERNAL (olddecl) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index e4da555..8a1cfbd 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -2797,7 +2797,7 @@ static char const *const merge_kind_name[MK_hwm] = NULL, NULL, "decl spec", "decl tmpl spec", /* 20,21 decl (template). */ - "alias spec", NULL, /* 22,23 alias. */ + "alias spec", "alias tmpl spec", /* 22,23 alias (template). */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; @@ -4144,10 +4144,17 @@ dumper::impl::nested_name (tree t) if (ti && TREE_CODE (TI_TEMPLATE (ti)) == TEMPLATE_DECL && (DECL_TEMPLATE_RESULT (TI_TEMPLATE (ti)) == t)) t = TI_TEMPLATE (ti); + tree not_tmpl = t; if (TREE_CODE (t) == TEMPLATE_DECL) - fputs ("template ", stream); + { + fputs ("template ", stream); + not_tmpl = DECL_TEMPLATE_RESULT (t); + } - if (DECL_LANG_SPECIFIC (t) && DECL_MODULE_IMPORT_P (t)) + if (not_tmpl + && DECL_P (not_tmpl) + && DECL_LANG_SPECIFIC (not_tmpl) + && DECL_MODULE_IMPORT_P (not_tmpl)) { /* We need to be careful here, so as to not explode on inconsistent data -- we're probably debugging, because @@ -4484,9 +4491,9 @@ trees_in::assert_definition (tree decl ATTRIBUTE_UNUSED, gcc_assert (!is_duplicate (decl) ? !slot : (slot - || !DECL_LANG_SPECIFIC (decl) - || !DECL_MODULE_PURVIEW_P (decl) - || (!DECL_MODULE_IMPORT_P (decl) + || !DECL_LANG_SPECIFIC (STRIP_TEMPLATE (decl)) + || !DECL_MODULE_PURVIEW_P (STRIP_TEMPLATE (decl)) + || (!DECL_MODULE_IMPORT_P (STRIP_TEMPLATE (decl)) && header_module_p ()))); if (TREE_CODE (decl) == TEMPLATE_DECL) @@ -7445,11 +7452,12 @@ trees_in::install_entity (tree decl) (*entity_ary)[ident] = decl; /* And into the entity map, if it's not already there. */ - if (!DECL_LANG_SPECIFIC (decl) - || !DECL_MODULE_ENTITY_P (decl)) + tree not_tmpl = STRIP_TEMPLATE (decl); + if (!DECL_LANG_SPECIFIC (not_tmpl) + || !DECL_MODULE_ENTITY_P (not_tmpl)) { - retrofit_lang_decl (decl); - DECL_MODULE_ENTITY_P (decl) = true; + retrofit_lang_decl (not_tmpl); + DECL_MODULE_ENTITY_P (not_tmpl) = true; /* Insert into the entity hash (it cannot already be there). */ bool existed; @@ -7510,12 +7518,11 @@ trees_out::decl_value (tree decl, depset *dep) tree o = get_originating_module_decl (decl); bool is_mod = false; - if (dep && dep->is_alias_tmpl_inst ()) - /* Alias template instantiations are templatey, but - found by name. */ - is_mod = false; - else if (DECL_LANG_SPECIFIC (o) && DECL_MODULE_PURVIEW_P (o)) + tree not_tmpl = STRIP_TEMPLATE (o); + if (DECL_LANG_SPECIFIC (not_tmpl) + && DECL_MODULE_PURVIEW_P (not_tmpl)) is_mod = true; + b (is_mod); } b (dep && dep->has_defn ()); @@ -7533,26 +7540,18 @@ trees_out::decl_value (tree decl, depset *dep) int inner_tag = 0; if (TREE_CODE (decl) == TEMPLATE_DECL) { - if (dep && dep->is_alias_tmpl_inst ()) - inner = NULL_TREE; - else - { - inner = DECL_TEMPLATE_RESULT (decl); - inner_tag = insert (inner, WK_value); - } + inner = DECL_TEMPLATE_RESULT (decl); + inner_tag = insert (inner, WK_value); if (streaming_p ()) { - int code = inner ? TREE_CODE (inner) : 0; + int code = TREE_CODE (inner); u (code); - if (inner) - { - start (inner, true); - tree_node_bools (inner); - dump (dumper::TREE) - && dump ("Writing %s:%d %C:%N%S", merge_kind_name[mk], inner_tag, - TREE_CODE (inner), inner, inner); - } + start (inner, true); + tree_node_bools (inner); + dump (dumper::TREE) + && dump ("Writing %s:%d %C:%N%S", merge_kind_name[mk], inner_tag, + TREE_CODE (inner), inner, inner); } } @@ -7560,7 +7559,7 @@ trees_out::decl_value (tree decl, depset *dep) int type_tag = 0; tree stub_decl = NULL_TREE; int stub_tag = 0; - if (inner && TREE_CODE (inner) == TYPE_DECL) + if (TREE_CODE (inner) == TYPE_DECL) { type = TREE_TYPE (inner); bool has_type = (type == TYPE_MAIN_VARIANT (type) @@ -7612,7 +7611,7 @@ trees_out::decl_value (tree decl, depset *dep) unsigned tpl_levels = 0; if (decl != inner) tpl_header (decl, &tpl_levels); - if (inner && TREE_CODE (inner) == FUNCTION_DECL) + if (TREE_CODE (inner) == FUNCTION_DECL) fn_parms_init (inner); /* Now write out the merging information, and then really @@ -7624,7 +7623,7 @@ trees_out::decl_value (tree decl, depset *dep) && dump ("Wrote:%d's %s merge key %C:%N", tag, merge_kind_name[mk], TREE_CODE (decl), decl); - if (inner && TREE_CODE (inner) == FUNCTION_DECL) + if (TREE_CODE (inner) == FUNCTION_DECL) fn_parms_fini (inner); if (!is_key_order ()) @@ -7636,18 +7635,6 @@ trees_out::decl_value (tree decl, depset *dep) tree_node_vals (inner); tpl_parms_fini (decl, tpl_levels); } - else if (!inner) - { - /* A template alias instantiation. */ - inner = DECL_TEMPLATE_RESULT (decl); - if (!is_key_order ()) - tree_node (inner); - if (streaming_p ()) - dump (dumper::TREE) - && dump ("Wrote(%d) alias template %C:%N", - get_tag (inner), TREE_CODE (inner), inner); - inner = NULL_TREE; - } if (type && !is_key_order ()) { @@ -7693,8 +7680,7 @@ trees_out::decl_value (tree decl, depset *dep) install_entity (decl, dep); } - if (inner - && VAR_OR_FUNCTION_DECL_P (inner) + if (VAR_OR_FUNCTION_DECL_P (inner) && DECL_LANG_SPECIFIC (inner) && DECL_MODULE_ATTACHMENTS_P (inner) && !is_key_order ()) @@ -7715,7 +7701,7 @@ trees_out::decl_value (tree decl, depset *dep) } bool is_typedef = false; - if (!type && inner && TREE_CODE (inner) == TYPE_DECL) + if (!type && TREE_CODE (inner) == TYPE_DECL) { tree t = TREE_TYPE (inner); unsigned tdef_flags = 0; @@ -7766,10 +7752,9 @@ trees_out::decl_value (tree decl, depset *dep) dump (dumper::TREE) && dump ("Written decl:%d %C:%N", tag, TREE_CODE (decl), decl); - if (!inner || NAMESPACE_SCOPE_P (inner)) - gcc_checking_assert (!inner - || !dep == (VAR_OR_FUNCTION_DECL_P (inner) - && DECL_LOCAL_DECL_P (inner))); + if (NAMESPACE_SCOPE_P (inner)) + gcc_checking_assert (!dep == (VAR_OR_FUNCTION_DECL_P (inner) + && DECL_LOCAL_DECL_P (inner))); else if ((TREE_CODE (inner) == TYPE_DECL && !is_typedef && TYPE_NAME (TREE_TYPE (inner)) == inner) @@ -7828,31 +7813,23 @@ trees_in::decl_value () if (decl && TREE_CODE (decl) == TEMPLATE_DECL) { int code = u (); - if (!code) - { - inner = NULL_TREE; - DECL_TEMPLATE_RESULT (decl) = error_mark_node; - } + inner = start (code); + if (inner && tree_node_bools (inner)) + DECL_TEMPLATE_RESULT (decl) = inner; else - { - inner = start (code); - if (inner && tree_node_bools (inner)) - DECL_TEMPLATE_RESULT (decl) = inner; - else - decl = NULL_TREE; + decl = NULL_TREE; - inner_tag = insert (inner); - if (decl) - dump (dumper::TREE) - && dump ("Reading:%d %C", inner_tag, TREE_CODE (inner)); - } + inner_tag = insert (inner); + if (decl) + dump (dumper::TREE) + && dump ("Reading:%d %C", inner_tag, TREE_CODE (inner)); } tree type = NULL_TREE; int type_tag = 0; tree stub_decl = NULL_TREE; int stub_tag = 0; - if (decl && inner && TREE_CODE (inner) == TYPE_DECL) + if (decl && TREE_CODE (inner) == TYPE_DECL) { if (unsigned type_code = u ()) { @@ -7917,7 +7894,7 @@ trees_in::decl_value () if (decl != inner) if (!tpl_header (decl, &tpl_levels)) goto bail; - if (inner && TREE_CODE (inner) == FUNCTION_DECL) + if (TREE_CODE (inner) == FUNCTION_DECL) parm_tag = fn_parms_init (inner); tree existing = key_mergeable (tag, mk, decl, inner, type, container, is_mod); @@ -7972,15 +7949,6 @@ trees_in::decl_value () if (!tpl_parms_fini (decl, tpl_levels)) goto bail; } - else if (!inner) - { - inner = tree_node (); - DECL_TEMPLATE_RESULT (decl) = inner; - TREE_TYPE (decl) = TREE_TYPE (inner); - dump (dumper::TREE) - && dump ("Read alias template %C:%N", TREE_CODE (inner), inner); - inner = NULL_TREE; - } if (type && (!tree_node_vals (type) || (stub_decl && !tree_node_vals (stub_decl)))) @@ -8009,8 +7977,7 @@ trees_in::decl_value () bool installed = install_entity (existing); bool is_new = existing == decl; - if (inner - && VAR_OR_FUNCTION_DECL_P (inner) + if (VAR_OR_FUNCTION_DECL_P (inner) && DECL_LANG_SPECIFIC (inner) && DECL_MODULE_ATTACHMENTS_P (inner)) { @@ -8039,7 +8006,7 @@ trees_in::decl_value () /* Regular typedefs will have a NULL TREE_TYPE at this point. */ unsigned tdef_flags = 0; bool is_typedef = false; - if (!type && inner && TREE_CODE (inner) == TYPE_DECL) + if (!type && TREE_CODE (inner) == TYPE_DECL) { tdef_flags = u (); if (tdef_flags & 1) @@ -8056,15 +8023,9 @@ trees_in::decl_value () if (installed) { - /* Mark the entity as imported and add it to the entity - array and map. */ - retrofit_lang_decl (decl); - DECL_MODULE_IMPORT_P (decl) = true; - if (inner_tag) - { - retrofit_lang_decl (inner); - DECL_MODULE_IMPORT_P (inner) = true; - } + /* Mark the entity as imported. */ + retrofit_lang_decl (inner); + DECL_MODULE_IMPORT_P (inner) = true; } if (spec.spec) @@ -8158,7 +8119,7 @@ trees_in::decl_value () if (!is_matching_decl (existing, decl, is_typedef)) unmatched_duplicate (existing); - if (inner && TREE_CODE (inner) == FUNCTION_DECL) + if (TREE_CODE (inner) == FUNCTION_DECL) { tree e_inner = STRIP_TEMPLATE (existing); for (auto parm = DECL_ARGUMENTS (inner); @@ -8211,8 +8172,7 @@ trees_in::decl_value () } } - if (inner - && !NAMESPACE_SCOPE_P (inner) + if (!NAMESPACE_SCOPE_P (inner) && ((TREE_CODE (inner) == TYPE_DECL && !is_typedef && TYPE_NAME (TREE_TYPE (inner)) == inner) @@ -8550,7 +8510,8 @@ trees_out::decl_node (tree decl, walk_kind ref) else if (TREE_CODE (ctx) != FUNCTION_DECL || TREE_CODE (decl) == TEMPLATE_DECL || (dep_hash->sneakoscope && DECL_IMPLICIT_TYPEDEF_P (decl)) - || (DECL_LANG_SPECIFIC (decl) && DECL_MODULE_IMPORT_P (decl))) + || (DECL_LANG_SPECIFIC (decl) + && DECL_MODULE_IMPORT_P (decl))) { auto kind = (TREE_CODE (decl) == NAMESPACE_DECL && !DECL_NAMESPACE_ALIAS (decl) @@ -8607,6 +8568,7 @@ trees_out::decl_node (tree decl, walk_kind ref) else { tree o = get_originating_module_decl (decl); + o = STRIP_TEMPLATE (o); kind = (DECL_LANG_SPECIFIC (o) && DECL_MODULE_PURVIEW_P (o) ? "purview" : "GMF"); } @@ -10371,7 +10333,7 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, gcc_checking_assert (match_mergeable_specialization (false, entry) == TREE_TYPE (existing)); - else if (mk & MK_tmpl_tmpl_mask) + if (mk & MK_tmpl_tmpl_mask) existing = DECL_TI_TEMPLATE (existing); } else @@ -10401,7 +10363,7 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, if (IDENTIFIER_CONV_OP_P (name)) name = conv_op_identifier; - if (inner && TREE_CODE (inner) == FUNCTION_DECL) + if (TREE_CODE (inner) == FUNCTION_DECL) { /* Functions are distinguished by parameter types. */ tree fn_type = TREE_TYPE (inner); @@ -10737,7 +10699,7 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, key.ret = tree_node (); else if (mk == MK_partial || ((mk == MK_named || mk == MK_friend_spec) - && inner && TREE_CODE (inner) == FUNCTION_DECL)) + && TREE_CODE (inner) == FUNCTION_DECL)) { key.ret = tree_node (); tree arg, *arg_ptr = &key.args; @@ -10760,11 +10722,8 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, DECL_NAME (decl) = name; DECL_CONTEXT (decl) = FROB_CONTEXT (container); } - if (inner) - { - DECL_NAME (inner) = DECL_NAME (decl); - DECL_CONTEXT (inner) = DECL_CONTEXT (decl); - } + DECL_NAME (inner) = DECL_NAME (decl); + DECL_CONTEXT (inner) = DECL_CONTEXT (decl); if (mk == MK_partial) { @@ -12383,20 +12342,9 @@ depset::hash::make_dependency (tree decl, entity_kind ek) gcc_checking_assert (TREE_CODE (decl) == OVERLOAD); if (TREE_CODE (decl) == TEMPLATE_DECL) - { - /* The template should have copied these from its result decl. */ - tree res = DECL_TEMPLATE_RESULT (decl); - - gcc_checking_assert (DECL_MODULE_EXPORT_P (decl) - == DECL_MODULE_EXPORT_P (res)); - if (DECL_LANG_SPECIFIC (res)) - { - gcc_checking_assert (DECL_MODULE_PURVIEW_P (decl) - == DECL_MODULE_PURVIEW_P (res)); - gcc_checking_assert ((DECL_MODULE_IMPORT_P (decl) - == DECL_MODULE_IMPORT_P (res))); - } - } + /* The template should have copied these from its result decl. */ + gcc_checking_assert (DECL_MODULE_EXPORT_P (decl) + == DECL_MODULE_EXPORT_P (DECL_TEMPLATE_RESULT (decl))); depset **slot = entity_slot (decl, true); depset *dep = *slot; @@ -12444,11 +12392,6 @@ depset::hash::make_dependency (tree decl, entity_kind ek) *slot = redirect; - if (DECL_LANG_SPECIFIC (decl)) - { - DECL_MODULE_IMPORT_P (partial) = DECL_MODULE_IMPORT_P (decl); - DECL_MODULE_PURVIEW_P (partial) = DECL_MODULE_PURVIEW_P (decl); - } depset *tmpl_dep = make_dependency (partial, EK_PARTIAL); gcc_checking_assert (tmpl_dep->get_entity_kind () == EK_PARTIAL); @@ -12478,46 +12421,48 @@ depset::hash::make_dependency (tree decl, entity_kind ek) && !(*eslot)->deps.length ()); } - if (ek != EK_USING - && DECL_LANG_SPECIFIC (decl) - && DECL_MODULE_IMPORT_P (decl)) + if (ek != EK_USING) { - /* Store the module number and index in cluster/section, so - we don't have to look them up again. */ - unsigned index = import_entity_index (decl); - module_state *from = import_entity_module (index); - /* Remap will be zero for imports from partitions, which we - want to treat as-if declared in this TU. */ - if (from->remap) + tree not_tmpl = STRIP_TEMPLATE (decl); + + if (DECL_LANG_SPECIFIC (not_tmpl) + && DECL_MODULE_IMPORT_P (not_tmpl)) { - dep->cluster = index - from->entity_lwm; - dep->section = from->remap; - dep->set_flag_bit (); + /* Store the module number and index in cluster/section, + so we don't have to look them up again. */ + unsigned index = import_entity_index (decl); + module_state *from = import_entity_module (index); + /* Remap will be zero for imports from partitions, which + we want to treat as-if declared in this TU. */ + if (from->remap) + { + dep->cluster = index - from->entity_lwm; + dep->section = from->remap; + dep->set_flag_bit (); + } } - } - if (ek == EK_DECL - && !dep->is_import () - && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL - && !(TREE_CODE (decl) == TEMPLATE_DECL - && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))) - { - tree ctx = CP_DECL_CONTEXT (decl); - tree not_tmpl = STRIP_TEMPLATE (decl); - - if (!TREE_PUBLIC (ctx)) - /* Member of internal namespace. */ - dep->set_flag_bit (); - else if (VAR_OR_FUNCTION_DECL_P (not_tmpl) - && DECL_THIS_STATIC (not_tmpl)) + if (ek == EK_DECL + && !dep->is_import () + && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL + && !(TREE_CODE (decl) == TEMPLATE_DECL + && DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))) { - /* An internal decl. This is ok in a GM entity. */ - if (!(header_module_p () - || !DECL_LANG_SPECIFIC (not_tmpl) - || !DECL_MODULE_PURVIEW_P (not_tmpl))) + tree ctx = CP_DECL_CONTEXT (decl); + + if (!TREE_PUBLIC (ctx)) + /* Member of internal namespace. */ dep->set_flag_bit (); + else if (VAR_OR_FUNCTION_DECL_P (not_tmpl) + && DECL_THIS_STATIC (not_tmpl)) + { + /* An internal decl. This is ok in a GM entity. */ + if (!(header_module_p () + || !DECL_LANG_SPECIFIC (not_tmpl) + || !DECL_MODULE_PURVIEW_P (not_tmpl))) + dep->set_flag_bit (); + } } - } if (!dep->is_import ()) @@ -18394,15 +18339,16 @@ int get_originating_module (tree decl, bool for_mangle) { tree owner = get_originating_module_decl (decl); + tree not_tmpl = STRIP_TEMPLATE (owner); - if (!DECL_LANG_SPECIFIC (owner)) + if (!DECL_LANG_SPECIFIC (not_tmpl)) return for_mangle ? -1 : 0; if (for_mangle - && (DECL_MODULE_EXPORT_P (owner) || !DECL_MODULE_PURVIEW_P (owner))) + && (DECL_MODULE_EXPORT_P (owner) || !DECL_MODULE_PURVIEW_P (not_tmpl))) return -1; - if (!DECL_MODULE_IMPORT_P (owner)) + if (!DECL_MODULE_IMPORT_P (not_tmpl)) return 0; return get_importing_module (owner); @@ -18426,7 +18372,8 @@ module_may_redeclare (tree decl) { module_state *me = (*modules)[0]; module_state *them = me; - if (DECL_LANG_SPECIFIC (decl) && DECL_MODULE_IMPORT_P (decl)) + tree not_tmpl = STRIP_TEMPLATE (decl); + if (DECL_LANG_SPECIFIC (not_tmpl) && DECL_MODULE_IMPORT_P (not_tmpl)) { /* We can be given the TEMPLATE_RESULT. We want the TEMPLATE_DECL. */ @@ -18468,15 +18415,15 @@ module_may_redeclare (tree decl) } if (me == them) - return ((DECL_LANG_SPECIFIC (decl) && DECL_MODULE_PURVIEW_P (decl)) + return ((DECL_LANG_SPECIFIC (not_tmpl) && DECL_MODULE_PURVIEW_P (not_tmpl)) == module_purview_p ()); if (!me->name) me = me->parent; /* We can't have found a GMF entity from a named module. */ - gcc_checking_assert (DECL_LANG_SPECIFIC (decl) - && DECL_MODULE_PURVIEW_P (decl)); + gcc_checking_assert (DECL_LANG_SPECIFIC (not_tmpl) + && DECL_MODULE_PURVIEW_P (not_tmpl)); return me && get_primary (them) == get_primary (me); } @@ -18500,20 +18447,16 @@ set_instantiating_module (tree decl) if (!modules_p ()) return; + decl = STRIP_TEMPLATE (decl); + if (!DECL_LANG_SPECIFIC (decl) && module_purview_p ()) retrofit_lang_decl (decl); + if (DECL_LANG_SPECIFIC (decl)) { DECL_MODULE_PURVIEW_P (decl) = module_purview_p (); /* If this was imported, we'll still be in the entity_hash. */ DECL_MODULE_IMPORT_P (decl) = false; - if (TREE_CODE (decl) == TEMPLATE_DECL) - { - tree res = DECL_TEMPLATE_RESULT (decl); - retrofit_lang_decl (res); - DECL_MODULE_PURVIEW_P (res) = DECL_MODULE_PURVIEW_P (decl); - DECL_MODULE_IMPORT_P (res) = false; - } } } @@ -18547,7 +18490,6 @@ set_defining_module (tree decl) gcc_checking_assert (!use_tpl); /* Get to the TEMPLATE_DECL. */ decl = TI_TEMPLATE (ti); - gcc_checking_assert (!DECL_MODULE_IMPORT_P (decl)); } /* Record it on the class_members list. */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index f4263f1..3bce3d5 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1666,8 +1666,9 @@ name_lookup::search_adl (tree fns, vec *args) continue; tree origin = get_originating_module_decl (TYPE_NAME (scope)); - if (!DECL_LANG_SPECIFIC (origin) - || !DECL_MODULE_IMPORT_P (origin)) + tree not_tmpl = STRIP_TEMPLATE (origin); + if (!DECL_LANG_SPECIFIC (not_tmpl) + || !DECL_MODULE_IMPORT_P (not_tmpl)) /* Not imported. */ continue; @@ -3680,6 +3681,7 @@ do_pushdecl (tree decl, bool hiding) if (iter.using_p ()) ; /* Ignore using decls here. */ else if (iter.hidden_p () + && TREE_CODE (*iter) == FUNCTION_DECL && DECL_LANG_SPECIFIC (*iter) && DECL_MODULE_IMPORT_P (*iter)) ; /* An undeclared builtin imported from elsewhere. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2736bb4..a056ece 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -4930,16 +4930,8 @@ build_template_decl (tree decl, tree parms, bool member_template_p) DECL_SOURCE_LOCATION (tmpl) = DECL_SOURCE_LOCATION (decl); DECL_MEMBER_TEMPLATE_P (tmpl) = member_template_p; - if (modules_p ()) - { - /* Propagate module information from the decl. */ - DECL_MODULE_EXPORT_P (tmpl) = DECL_MODULE_EXPORT_P (decl); - if (DECL_LANG_SPECIFIC (decl)) - { - DECL_MODULE_PURVIEW_P (tmpl) = DECL_MODULE_PURVIEW_P (decl); - gcc_checking_assert (!DECL_MODULE_IMPORT_P (decl)); - } - } + /* Propagate module information from the decl. */ + DECL_MODULE_EXPORT_P (tmpl) = DECL_MODULE_EXPORT_P (decl); return tmpl; } @@ -10167,25 +10159,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, } /* Build template info for the new specialization. */ - if (TYPE_ALIAS_P (t)) - { - /* This is constructed during instantiation of the alias - decl. But for member templates of template classes, that - is not correct as we need to refer to the partially - instantiated template, not the most general template. - The incorrect knowledge will not have escaped this - instantiation process, so we're good just updating the - template_info we made then. */ - tree ti = DECL_TEMPLATE_INFO (TYPE_NAME (t)); - gcc_checking_assert (template_args_equal (TI_ARGS (ti), arglist)); - if (TI_TEMPLATE (ti) != found) - { - gcc_checking_assert (DECL_TI_TEMPLATE (found) == TI_TEMPLATE (ti)); - TI_TEMPLATE (ti) = found; - } - } - else - SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist)); + SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist)); elt.spec = t; slot = type_specializations->find_slot_with_hash (&elt, hash, INSERT); @@ -14297,8 +14271,7 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain, } else { - if (TREE_CODE (decl) != TYPE_DECL || !TYPE_DECL_ALIAS_P (decl)) - DECL_TI_TEMPLATE (inner) = r; + DECL_TI_TEMPLATE (inner) = r; DECL_TI_ARGS (r) = DECL_TI_ARGS (inner); } @@ -14311,17 +14284,13 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain, /* Propagate module information from the decl. */ DECL_MODULE_EXPORT_P (r) = DECL_MODULE_EXPORT_P (inner); if (DECL_LANG_SPECIFIC (inner)) - { - DECL_MODULE_PURVIEW_P (r) = DECL_MODULE_PURVIEW_P (inner); - /* If this is a constrained template, the above tsubst of - inner can find the unconstrained template, which may have - come from an import. This is ok, because we don't - register this instantiation (see below). */ - gcc_checking_assert (!DECL_MODULE_IMPORT_P (inner) - || (TEMPLATE_PARMS_CONSTRAINTS - (DECL_TEMPLATE_PARMS (t)))); - DECL_MODULE_IMPORT_P (r) = false; - } + /* If this is a constrained template, the above tsubst of + inner can find the unconstrained template, which may have + come from an import. This is ok, because we don't + register this instantiation (see below). */ + gcc_checking_assert (!DECL_MODULE_IMPORT_P (inner) + || (TEMPLATE_PARMS_CONSTRAINTS + (DECL_TEMPLATE_PARMS (t)))); } DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE; -- cgit v1.1 From c453a817129c2c362726a9773390419f1df7dda3 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 26 Mar 2021 11:20:03 -0400 Subject: c++: ICE on invalid with NSDMI in C++98 [PR98352] NSDMIs are a C++11 thing, and here we ICE with them on the non-C++11 path. Fortunately all we need is a small tweak to my recent r11-7835 patch. gcc/cp/ChangeLog: PR c++/98352 * method.c (implicitly_declare_fn): Pass &raises to synthesized_method_walk. gcc/testsuite/ChangeLog: PR c++/98352 * g++.dg/cpp0x/inh-ctor37.C: Remove dg-error. * g++.dg/cpp0x/nsdmi17.C: New test. --- gcc/cp/method.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 25c1e68..8ae7496 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -3002,7 +3002,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, member initializer (c++/89914). Also, in C++98, we might have failed to deduce RAISES, so try again but complain this time. */ if (cxx_dialect < cxx11) - synthesized_method_walk (type, kind, const_p, nullptr, nullptr, + synthesized_method_walk (type, kind, const_p, &raises, nullptr, nullptr, nullptr, /*diag=*/true, &inherited_ctor, inherited_parms); /* We should have seen an error at this point. */ -- cgit v1.1 From 651684b462f979a4e70a668c4c9767a5fd7d223a Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 27 Mar 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ba750a2..eb48265 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,44 @@ +2021-03-26 Marek Polacek + + PR c++/98352 + * method.c (implicitly_declare_fn): Pass &raises to + synthesized_method_walk. + +2021-03-26 Nathan Sidwell + + PR c++/99283 + * cp-tree.h (DECL_MODULE_CHECK): Ban TEMPLATE_DECL. + (SET_TYPE_TEMPLATE_INFO): Restore Alias template setting. + * decl.c (duplicate_decls): Remove template_decl module flag + propagation. + * module.cc (merge_kind_name): Add alias tmpl spec as a thing. + (dumper::impl::nested_name): Adjust for template-decl module flag + change. + (trees_in::assert_definition): Likewise. + (trees_in::install_entity): Likewise. + (trees_out::decl_value): Likewise. Remove alias template + separation of template and type_decl. + (trees_in::decl_value): Likewise. + (trees_out::key_mergeable): Likewise, + (trees_in::key_mergeable): Likewise. + (trees_out::decl_node): Adjust for template-decl module flag + change. + (depset::hash::make_dependency): Likewise. + (get_originating_module, module_may_redeclare): Likewise. + (set_instantiating_module, set_defining_module): Likewise. + * name-lookup.c (name_lookup::search_adl): Likewise. + (do_pushdecl): Likewise. + * pt.c (build_template_decl): Likewise. + (lookup_template_class_1): Remove special alias_template handling + of DECL_TI_TEMPLATE. + (tsubst_template_decl): Likewise. + +2021-03-26 Jakub Jelinek + + PR c++/99705 + * tree.c (bot_manip): Remap artificial automatic temporaries mentioned + in DECL_EXPR or in BIND_EXPR_VARS. + 2021-03-25 Jakub Jelinek PR c++/99672 -- cgit v1.1 From 953624089be3f51c2ebacba65be8521bf6ae8430 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 30 Mar 2021 18:15:32 +0200 Subject: c++: Fix ICE on PTRMEM_CST in lambda in inline var initializer [PR99790] The following testcase ICEs (since the addition of inline var support), because the lambda contains PTRMEM_CST but finish_function is called for the lambda quite early during parsing it (from finish_lambda_function) when the containing class is still incomplete. That means that during genericization cplus_expand_constant keeps the PTRMEM_CST unmodified, but later nothing lowers it when the class is finalized. Using sizeof etc. on the class in such contexts is rejected by both g++ and clang++, and when the PTRMEM_CST appears e.g. in static var initializers rather than in functions, we handle it correctly because c_parse_final_cleanups -> lower_var_init will handle those cplus_expand_constant when all classes are already finalized. The following patch fixes it by calling cplus_expand_constant again during gimplification, as we are now unconditionally unit at a time, I'd think everything that could be completed will be before we start gimplification. 2021-03-30 Jakub Jelinek PR c++/99790 * cp-gimplify.c (cp_gimplify_expr): Handle PTRMEM_CST. * g++.dg/cpp1z/pr99790.C: New test. --- gcc/cp/cp-gimplify.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 4baa336..9079a5b 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -660,6 +660,14 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) ret = GS_UNHANDLED; break; + case PTRMEM_CST: + *expr_p = cplus_expand_constant (*expr_p); + if (TREE_CODE (*expr_p) == PTRMEM_CST) + ret = GS_ERROR; + else + ret = GS_OK; + break; + case RETURN_EXPR: if (TREE_OPERAND (*expr_p, 0) && (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == INIT_EXPR -- cgit v1.1 From 5f3c6027257118469a722816e228394b5978ddb0 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Tue, 30 Mar 2021 09:45:59 -0700 Subject: c++: duplicate const static members [PR 99283] This is the bug that keeps on giving. Reducing it has been successful at hitting other defects. In this case, some more specialization hash table fun, plus an issue with reading in a definition of a duplicated declaration. At least I discovered a null context check is no longer needed. PR c++/99283 gcc/cp/ * module.cc (dumper::operator): Make less brittle. (trees_out::core_bools): VAR_DECLs always have a context. (trees_out::key_mergeable): Use same_type_p for asserting. (trees_in::read_var_def): Propagate DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P. gcc/testsuite/ * g++.dg/modules/pr99283-5.h: New. * g++.dg/modules/pr99283-5_a.H: New. * g++.dg/modules/pr99283-5_b.H: New. * g++.dg/modules/pr99283-5_c.C: New. --- gcc/cp/module.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 8a1cfbd..fab6b57 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -4325,8 +4325,8 @@ dumper::operator () (const char *format, ...) case 'N': /* Name. */ { tree t = va_arg (args, tree); - if (t && TREE_CODE (t) == OVERLOAD) - t = OVL_FIRST (t); + while (t && TREE_CODE (t) == OVERLOAD) + t = OVL_FUNCTION (t); fputc ('\'', dumps->stream); dumps->nested_name (t); fputc ('\'', dumps->stream); @@ -5206,8 +5206,7 @@ trees_out::core_bools (tree t) else if (code == VAR_DECL) { /* This is DECL_INITIALIZED_P. */ - if (DECL_CONTEXT (t) - && TREE_CODE (DECL_CONTEXT (t)) != FUNCTION_DECL) + if (TREE_CODE (DECL_CONTEXT (t)) != FUNCTION_DECL) /* We'll set this when reading the definition. */ flag_1 = false; } @@ -10331,8 +10330,8 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, if (mk & MK_tmpl_alias_mask) /* It should be in both tables. */ gcc_checking_assert - (match_mergeable_specialization (false, entry) - == TREE_TYPE (existing)); + (same_type_p (match_mergeable_specialization (false, entry), + TREE_TYPE (existing))); if (mk & MK_tmpl_tmpl_mask) existing = DECL_TI_TEMPLATE (existing); } @@ -10345,7 +10344,10 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, } /* The walkabout should have found ourselves. */ - gcc_checking_assert (existing == decl); + gcc_checking_assert (TREE_CODE (decl) == TYPE_DECL + ? same_type_p (TREE_TYPE (decl), + TREE_TYPE (existing)) + : existing == decl); } } else if (mk != MK_unique) @@ -11513,7 +11515,11 @@ trees_in::read_var_def (tree decl, tree maybe_template) if (DECL_EXTERNAL (decl)) DECL_NOT_REALLY_EXTERN (decl) = true; if (VAR_P (decl)) - DECL_INITIALIZED_P (decl) = true; + { + DECL_INITIALIZED_P (decl) = true; + if (maybe_dup && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (maybe_dup)) + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true; + } DECL_INITIAL (decl) = init; if (!dyn_init) ; -- cgit v1.1 From 08d2edae5d84209c0dcf327a13d4f6b4eacdb1ac Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 31 Mar 2021 00:16:31 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index eb48265..d4c317c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2021-03-30 Nathan Sidwell + + PR c++/99283 + * module.cc (dumper::operator): Make less brittle. + (trees_out::core_bools): VAR_DECLs always have a context. + (trees_out::key_mergeable): Use same_type_p for asserting. + (trees_in::read_var_def): Propagate + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P. + +2021-03-30 Jakub Jelinek + + PR c++/99790 + * cp-gimplify.c (cp_gimplify_expr): Handle PTRMEM_CST. + 2021-03-26 Marek Polacek PR c++/98352 -- cgit v1.1 From 0bbf0edbfc782f8e4e416d5fbd1b52a515adb585 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 30 Mar 2021 22:54:37 -0400 Subject: c++: placeholder type constraint and argument pack [PR99815] When checking dependence of a placeholder type constraint, if the first template argument of the constraint is an argument pack, we need to expand it in order to properly separate the implicit 'auto' argument from the rest. gcc/cp/ChangeLog: PR c++/99815 * pt.c (placeholder_type_constraint_dependent_p): Expand argument packs to separate the first non-pack argument from the rest. gcc/testsuite/ChangeLog: PR c++/99815 * g++.dg/cpp2a/concepts-placeholder5.C: New test. --- gcc/cp/pt.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a056ece..dc6f2f3 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -28189,6 +28189,11 @@ placeholder_type_constraint_dependent_p (tree t) tree id = unpack_concept_check (t); tree args = TREE_OPERAND (id, 1); tree first = TREE_VEC_ELT (args, 0); + if (ARGUMENT_PACK_P (first)) + { + args = expand_template_argument_pack (args); + first = TREE_VEC_ELT (args, 0); + } gcc_checking_assert (TREE_CODE (first) == WILDCARD_DECL || is_auto (first)); for (int i = 1; i < TREE_VEC_LENGTH (args); ++i) -- cgit v1.1 From a3bf6ce7f2e17f2c977c13df23eb718e7b433dcd Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 30 Mar 2021 22:57:11 -0400 Subject: c++: Adjust mangling of __alignof__ [PR88115] r11-4926 made __alignof__ get mangled differently from alignof, encoding __alignof__ as a vendor extended operator. But this mangling is problematic for the reasons mentioned in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88115#c6. This patch changes our mangling of __alignof__ to instead use the new "vendor extended expression" syntax that's proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/112. Clang does the same thing already, so after this patch Clang and GCC agree about the mangling of __alignof__(type) and __alignof__(expr). gcc/cp/ChangeLog: PR c++/88115 * mangle.c (write_expression): Adjust the mangling of __alignof__. include/ChangeLog: PR c++/88115 * demangle.h (enum demangle_component_type): Add DEMANGLE_COMPONENT_VENDOR_EXPR. libiberty/ChangeLog: PR c++/88115 * cp-demangle.c (d_dump, d_make_comp, d_expression_1) (d_count_templates_scopes): Handle DEMANGLE_COMPONENT_VENDOR_EXPR. (d_print_comp_inner): Likewise. : Revert r11-4926 change. : Likewise. * testsuite/demangle-expected: Adjust __alignof__ tests. gcc/testsuite/ChangeLog: PR c++/88115 * g++.dg/cpp0x/alignof7.C: Adjust expected mangling. --- gcc/cp/mangle.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 0a9e5aa..57ce9a6 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -3124,11 +3124,9 @@ write_expression (tree expr) if (abi_version_at_least (15)) { /* We used to mangle __alignof__ like alignof. */ - write_string ("v111__alignof__"); - if (TYPE_P (TREE_OPERAND (expr, 0))) - write_type (TREE_OPERAND (expr, 0)); - else - write_expression (TREE_OPERAND (expr, 0)); + write_string ("u11__alignof__"); + write_template_arg (TREE_OPERAND (expr, 0)); + write_char ('E'); return; } } -- cgit v1.1 From a2531859bf5bf6cf1f29c0dca85fd26e80904a5d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 30 Mar 2021 20:31:18 -0400 Subject: c++: Alias template in pack expansion [PR99445] In this testcase, iterative_hash_template_arg checks alias_template_specialization_p to determine whether to treat a type as a dependent alias, and structural_comptypes checks dependent_alias_template_spec_p. Normally that difference isn't a problem because canonicalizing template arguments strips non-dependent aliases, but that wasn't happening for the pack expansion. Fixed thus. gcc/cp/ChangeLog: PR c++/99445 * tree.c (strip_typedefs): Handle TYPE_PACK_EXPANSION. gcc/testsuite/ChangeLog: PR c++/99445 * g++.dg/cpp0x/alias-decl-variadic1.C: New test. --- gcc/cp/tree.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8c4bd15..dca947b 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1722,6 +1722,15 @@ strip_typedefs (tree t, bool *remove_attributes, unsigned int flags) remove_attributes, flags); result = finish_underlying_type (type); break; + case TYPE_PACK_EXPANSION: + type = strip_typedefs (PACK_EXPANSION_PATTERN (t), + remove_attributes, flags); + if (type != PACK_EXPANSION_PATTERN (t)) + { + result = copy_node (t); + PACK_EXPANSION_PATTERN (result) = type; + } + break; default: break; } -- cgit v1.1 From 95d217ab52d31dc06fda42fc136dea165909e88b Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 1 Apr 2021 00:16:39 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d4c317c..1020047 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2021-03-31 Jason Merrill + + PR c++/99445 + * tree.c (strip_typedefs): Handle TYPE_PACK_EXPANSION. + +2021-03-31 Patrick Palka + + PR c++/88115 + * mangle.c (write_expression): Adjust the mangling of + __alignof__. + +2021-03-31 Patrick Palka + + PR c++/99815 + * pt.c (placeholder_type_constraint_dependent_p): Expand + argument packs to separate the first non-pack argument + from the rest. + 2021-03-30 Nathan Sidwell PR c++/99283 -- cgit v1.1 From 584731ecedf09c2c067913c4af9ed0a30cf19e8d Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 1 Apr 2021 05:25:53 -0700 Subject: c++: inter-cluster import order [PR 99283] I finally managed to reduce the testcase without hitting other bugs. This problem is caused by discovering a duplicate in the middle of reading in the entity in question. I had thougt the import seeding at the beginning of a cluster prevented that, but it is insufficient. Specifically an earlier cluster in the same module can cause the import of a duplicate. Although clusters within a module are well-ordered, there is no ordering between clusters of one module and clusters of another module. And thus we can get duplicate declaration loops. This prevents the problem by also seeding references to earlier clusters in the same module. As the FIXME notes, it is sufficient to reference a single entity in any particular earlier cluster, plus, we also could determine the implicit dependencies and prune that seeding even further. I do not do that -- it decrease the loading that will happen, but would reduce the serialization size. As ever, let's get correctness first. PR c++/99283 gcc/cp/ * module.cc (trees_out::decl_node): Adjust importedness reference assert. (module_state::intercluster_seed): New. Seed both imports and inter-cluster references. Broken out of ... (module_state::write_cluster): ... here. Call it. gcc/testsuite/ * g++.dg/modules/pr99283-6.h: New. * g++.dg/modules/pr99283-6_a.H: New. * g++.dg/modules/pr99283-6_b.H: New. * g++.dg/modules/pr99283-6_c.C: New. * g++.dg/modules/hdr-init-1_c.C: Adjust scan. * g++.dg/modules/indirect-3_c.C: Adjust scan. * g++.dg/modules/indirect-4_c.C: Adjust scan. * g++.dg/modules/lambda-3_b.C: Adjust scan. * g++.dg/modules/late-ret-3_c.C: Adjust scan. * g++.dg/modules/pr99425-1_b.H: Adjust scan. * g++.dg/modules/pr99425-1_c.C: Adjust scan. --- gcc/cp/module.cc | 63 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 26 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index fab6b57..c87ddd1 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -3570,6 +3570,7 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state { unsigned, unsigned *crc_ptr); bool read_namespaces (unsigned); + void intercluster_seed (trees_out &sec, unsigned index, depset *dep); unsigned write_cluster (elf_out *to, depset *depsets[], unsigned size, depset::hash &, unsigned *counts, unsigned *crc_ptr); bool read_cluster (unsigned snum); @@ -8548,8 +8549,7 @@ trees_out::decl_node (tree decl, walk_kind ref) gcc_checking_assert (index == ~import_entity_index (decl)); #if CHECKING_P - if (importedness) - gcc_assert (!import == (importedness < 0)); + gcc_assert (!import || importedness >= 0); #endif i (tt_entity); u (import); @@ -14419,7 +14419,33 @@ enum ct_bind_flags cbf_wrapped = 0x8, /* ... that is wrapped. */ }; -/* Write the cluster of depsets in SCC[0-SIZE). */ +/* DEP belongs to a different cluster, seed it to prevent + unfortunately timed duplicate import. */ +// FIXME: QOI For inter-cluster references we could just only pick +// one entity from an earlier cluster. Even better track +// dependencies between earlier clusters + +void +module_state::intercluster_seed (trees_out &sec, unsigned index_hwm, depset *dep) +{ + if (dep->is_import () + || dep->cluster < index_hwm) + { + tree ent = dep->get_entity (); + if (!TREE_VISITED (ent)) + { + sec.tree_node (ent); + dump (dumper::CLUSTER) + && dump ("Seeded %s %N", + dep->is_import () ? "import" : "intercluster", ent); + } + } +} + +/* Write the cluster of depsets in SCC[0-SIZE). + dep->section -> section number + dep->cluster -> entity number + */ unsigned module_state::write_cluster (elf_out *to, depset *scc[], unsigned size, @@ -14431,6 +14457,7 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size, trees_out sec (to, this, table, table.section); sec.begin (); + unsigned index_lwm = counts[MSC_entities]; /* Determine entity numbers, mark for writing. */ dump (dumper::CLUSTER) && dump ("Cluster members:") && (dump.indent (), true); @@ -14484,10 +14511,10 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size, } dump (dumper::CLUSTER) && (dump.outdent (), true); - /* Ensure every imported decl is referenced before we start - streaming. This ensures that we never encounter the situation - where this cluster instantiates some implicit member that - importing some other decl causes to be instantiated. */ + /* Ensure every out-of-cluster decl is referenced before we start + streaming. We must do both imports *and* earlier clusters, + because the latter could reach into the former and cause a + duplicate loop. */ sec.set_importing (+1); for (unsigned ix = 0; ix != size; ix++) { @@ -14505,30 +14532,14 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size, depset *bind = dep->deps[ix]; if (bind->get_entity_kind () == depset::EK_USING) bind = bind->deps[1]; - if (bind->is_import ()) - { - tree import = bind->get_entity (); - if (!TREE_VISITED (import)) - { - sec.tree_node (import); - dump (dumper::CLUSTER) - && dump ("Seeded import %N", import); - } - } + + intercluster_seed (sec, index_lwm, bind); } /* Also check the namespace itself. */ dep = dep->deps[0]; } - if (dep->is_import ()) - { - tree import = dep->get_entity (); - if (!TREE_VISITED (import)) - { - sec.tree_node (import); - dump (dumper::CLUSTER) && dump ("Seeded import %N", import); - } - } + intercluster_seed (sec, index_lwm, dep); } } sec.tree_node (NULL_TREE); -- cgit v1.1 From 5f00df5925082c7b66da91270f2ed29bf4818c93 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 31 Mar 2021 17:48:50 -0400 Subject: c++: Add ABI version for PR98481 fix The PR98481 fix corrects an ABI regression in GCC 10, but we don't want to introduce an ABI change in the middle of the GCC 10 cycle. This patch introduces ABI v15 for the fix, which will be available but not default in GCC 10.3; the broken behavior remains in ABI v14. Compatibility aliases will not be generated for this change. gcc/ChangeLog: PR c++/98481 * common.opt: Document v15 and v16. gcc/c-family/ChangeLog: PR c++/98481 * c-opts.c (c_common_post_options): Bump latest_abi_version. gcc/cp/ChangeLog: PR c++/98481 * mangle.c (write_expression): Adjust. * class.c (find_abi_tags_r): Disable PR98481 fix for ABI v14. (mark_abi_tags_r): Likewise. gcc/testsuite/ChangeLog: PR c++/98481 * g++.dg/abi/abi-tag24a.C: New test. * g++.dg/abi/macro0.C: Adjust expected value. --- gcc/cp/class.c | 6 +++--- gcc/cp/mangle.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 856e81e..4bffec4 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1494,8 +1494,8 @@ mark_or_check_tags (tree t, tree *tp, abi_tag_data *p, bool val) static tree find_abi_tags_r (tree *tp, int *walk_subtrees, void *data) { - if (TYPE_P (*tp) && *walk_subtrees == 1) - /* Tell cp_walk_subtrees to look though typedefs. */ + if (TYPE_P (*tp) && *walk_subtrees == 1 && flag_abi_version != 14) + /* Tell cp_walk_subtrees to look though typedefs. [PR98481] */ *walk_subtrees = 2; if (!OVERLOAD_TYPE_P (*tp)) @@ -1518,7 +1518,7 @@ find_abi_tags_r (tree *tp, int *walk_subtrees, void *data) static tree mark_abi_tags_r (tree *tp, int *walk_subtrees, void *data) { - if (TYPE_P (*tp) && *walk_subtrees == 1) + if (TYPE_P (*tp) && *walk_subtrees == 1 && flag_abi_version != 14) /* Tell cp_walk_subtrees to look though typedefs. */ *walk_subtrees = 2; diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 57ce9a6..6c11134 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -3119,9 +3119,9 @@ write_expression (tree expr) { if (!ALIGNOF_EXPR_STD_P (expr)) { - if (abi_warn_or_compat_version_crosses (15)) + if (abi_warn_or_compat_version_crosses (16)) G.need_abi_warning = true; - if (abi_version_at_least (15)) + if (abi_version_at_least (16)) { /* We used to mangle __alignof__ like alignof. */ write_string ("u11__alignof__"); @@ -3350,9 +3350,9 @@ write_expression (tree expr) tree name = dependent_name (expr); if (IDENTIFIER_ANY_OP_P (name)) { - if (abi_version_at_least (15)) + if (abi_version_at_least (16)) write_string ("on"); - if (abi_warn_or_compat_version_crosses (15)) + if (abi_warn_or_compat_version_crosses (16)) G.need_abi_warning = 1; } write_unqualified_id (name); -- cgit v1.1 From af78514a18ca5c9aaa10813bb4dc639d7ccdf0cc Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Tue, 30 Mar 2021 14:56:39 +0100 Subject: modules : Make sure we include in system.h. It appears that many targets include the map header transitively in other std headers included from system.h. However there are some editions of clang/libc++ in Xcode that do not, which results in a bootstrap fail - since when resolver.h is included there is then a conflict in declaring abort(). The fix is to ensure that map is pulled in by system.h and before resolver.h is included. As a precautionary measure and to alert anyone perhaps adding another header to resolver.h this patch also gates the direct includes there on !IN_GCC. c++tools/ChangeLog: * resolver.h: Do not include std headers directly when building in GCC. gcc/cp/ChangeLog: * mapper-client.cc (INCLUDE_MAP): New; require map to be included from system.h. * mapper-resolver.cc (INCLUDE_MAP): Likewise. --- gcc/cp/mapper-client.cc | 1 + gcc/cp/mapper-resolver.cc | 1 + 2 files changed, 2 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/mapper-client.cc b/gcc/cp/mapper-client.cc index 774e2b2..b9e0216 100644 --- a/gcc/cp/mapper-client.cc +++ b/gcc/cp/mapper-client.cc @@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see #endif #define INCLUDE_STRING #define INCLUDE_VECTOR +#define INCLUDE_MAP #include "system.h" #include "line-map.h" diff --git a/gcc/cp/mapper-resolver.cc b/gcc/cp/mapper-resolver.cc index bcf6c88..db443fb 100644 --- a/gcc/cp/mapper-resolver.cc +++ b/gcc/cp/mapper-resolver.cc @@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see #define INCLUDE_STRING #define INCLUDE_VECTOR #define INCLUDE_ALGORITHM +#define INCLUDE_MAP #include "system.h" // We don't want or need to be aware of networking -- cgit v1.1 From 0cf4813202f19768e31666f6aa82bde4dce4065a Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 1 Apr 2021 15:17:40 -0400 Subject: c++: variadic lambda noexcept-specifier [PR99583] The tree-walk looking for parameter packs didn't find this one because we weren't stepping into TYPE_RAISES_EXCEPTIONS. gcc/cp/ChangeLog: PR c++/99583 PR c++/99584 * tree.c (cp_walk_subtrees) [FUNCTION_TYPE]: Walk into TYPE_RAISES_EXCEPTIONS. gcc/testsuite/ChangeLog: PR c++/99583 * g++.dg/cpp0x/lambda/lambda-variadic12.C: New test. --- gcc/cp/tree.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index dca947b..13cc61c 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -5415,6 +5415,11 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, } break; + case FUNCTION_TYPE: + case METHOD_TYPE: + WALK_SUBTREE (TYPE_RAISES_EXCEPTIONS (*tp)); + break; + default: return NULL_TREE; } -- cgit v1.1 From 6a60ffc297b9d4903543a25538e62e7fb39420a9 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 1 Apr 2021 10:42:43 -0400 Subject: c++: GC collects live data when synthesizing operator== [PR99831] Here we crash in reshape_init because we're accessing ggc_freed & poisoned data: since r277865 in defaulted_late_check we call synthesize_method here: if (kind == sfk_comparison) { /* If the function was declared constexpr, check that the definition qualifies. Otherwise we can define the function lazily. */ if (DECL_DECLARED_CONSTEXPR_P (fn) && !DECL_INITIAL (fn)) synthesize_method (fn); return; } which in this test triggers when we're processing the string<"a">{} in the static_assert. First, we create a CONSTRUCTOR for the "{}" in cp_parser_functional_cast, then we call finish_compound_literal which calls complete_type and that results in garbage collection, which then frees the CONSTRUCTOR {} we created when parsing the braced-list in string<"a">{} -- at this point, it's not referenced by anything. (That's not the case for 'type' in finish_compound_literal: the symbol table contains a node for operator==, so ggc_mark_roots goes and marks the fn decl, its type, its arguments etc., as used, so we don't collect it.) We could just bump function_depth around the new call to synthesize_method to prevent GC. gcc/cp/ChangeLog: PR c++/99831 * method.c (defaulted_late_check): ++ and -- function_depth around the call to synthesize_method. * pt.c: Remove the saved_trees global. gcc/testsuite/ChangeLog: PR c++/99831 * g++.dg/other/gc6.C: New test. --- gcc/cp/method.c | 7 ++++++- gcc/cp/pt.c | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 8ae7496..0f416be 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -3131,7 +3131,12 @@ defaulted_late_check (tree fn) /* If the function was declared constexpr, check that the definition qualifies. Otherwise we can define the function lazily. */ if (DECL_DECLARED_CONSTEXPR_P (fn) && !DECL_INITIAL (fn)) - synthesize_method (fn); + { + /* Prevent GC. */ + function_depth++; + synthesize_method (fn); + function_depth--; + } return; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index dc6f2f3..7956e83 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -65,7 +65,6 @@ static GTY(()) struct pending_template *last_pending_template; int processing_template_parmlist; static int template_header_count; -static GTY(()) tree saved_trees; static vec inline_parm_levels; static GTY(()) struct tinst_level *current_tinst_level; -- cgit v1.1 From f1607029aea3043f7bd4f86c005e0997795f5ffd Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 2 Apr 2021 00:16:26 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1020047..d0aa8a5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,39 @@ +2021-04-01 Marek Polacek + + PR c++/99831 + * method.c (defaulted_late_check): ++ and -- function_depth around + the call to synthesize_method. + * pt.c: Remove the saved_trees global. + +2021-04-01 Jason Merrill + + PR c++/99583 + PR c++/99584 + * tree.c (cp_walk_subtrees) [FUNCTION_TYPE]: Walk into + TYPE_RAISES_EXCEPTIONS. + +2021-04-01 Iain Sandoe + + * mapper-client.cc (INCLUDE_MAP): New; require map to be + included from system.h. + * mapper-resolver.cc (INCLUDE_MAP): Likewise. + +2021-04-01 Jason Merrill + + PR c++/98481 + * mangle.c (write_expression): Adjust. + * class.c (find_abi_tags_r): Disable PR98481 fix for ABI v14. + (mark_abi_tags_r): Likewise. + +2021-04-01 Nathan Sidwell + + PR c++/99283 + * module.cc (trees_out::decl_node): Adjust importedness reference + assert. + (module_state::intercluster_seed): New. Seed both imports and + inter-cluster references. Broken out of ... + (module_state::write_cluster): ... here. Call it. + 2021-03-31 Jason Merrill PR c++/99445 -- cgit v1.1 From f4e05eebd6aac6118cbd9e0a04c011b6ed682826 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Fri, 2 Apr 2021 06:28:29 -0700 Subject: c++: header unit purview [PR 99283] This case occurs due to some equivocation about module_purview. Header-unit building is treated as a module-purview, but we should not treat entities imported from that as module purview. (header units were not a thing when I started). The testcase didn't understand we had a local textual definition, but it was (incorrectly) marked as module-purview, because we'd read in a declaration from a header unit too. gcc/cp/ * cp-tree.h (lang_decl_base): Correct module flag comment. * module.cc (trees_in::assert_definition): Break out not_tmpl var. (trees_out::lang_decl_bools): Do not write purview for header units. gcc/testsuite/ * g++.dg/modules/pr99283-6_d.H: New. * g++.dg/modules/pr99283-7-swap.h: New. * g++.dg/modules/pr99283-7-traits.h: New. * g++.dg/modules/pr99283-7_a.H: New. * g++.dg/modules/pr99283-7_b.H: New. * g++.dg/modules/pr99283-7_c.C: New. * g++.dg/modules/pr99283-7_d.H: New. --- gcc/cp/cp-tree.h | 4 ++-- gcc/cp/module.cc | 17 ++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9535910..66bba7b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2756,8 +2756,8 @@ struct GTY(()) lang_decl_base { unsigned var_declared_inline_p : 1; /* var */ unsigned dependent_init_p : 1; /* var */ - /* The following apply to VAR, FUNCTION, TYPE, CONCEPT, TEMPLATE, - NAMESPACE decls. */ + /* The following apply to VAR, FUNCTION, TYPE, CONCEPT, & NAMESPACE + decls. */ unsigned module_purview_p : 1; /* in module purview (not GMF) */ unsigned module_import_p : 1; /* from an import */ unsigned module_entity_p : 1; /* is in the entitity ary & diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index c87ddd1..d5b7d28 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -4477,6 +4477,7 @@ trees_in::assert_definition (tree decl ATTRIBUTE_UNUSED, { #if CHECKING_P tree *slot = note_defs->find_slot (decl, installing ? INSERT : NO_INSERT); + tree not_tmpl = STRIP_TEMPLATE (decl); if (installing) { /* We must be inserting for the first time. */ @@ -4492,13 +4493,13 @@ trees_in::assert_definition (tree decl ATTRIBUTE_UNUSED, gcc_assert (!is_duplicate (decl) ? !slot : (slot - || !DECL_LANG_SPECIFIC (STRIP_TEMPLATE (decl)) - || !DECL_MODULE_PURVIEW_P (STRIP_TEMPLATE (decl)) - || (!DECL_MODULE_IMPORT_P (STRIP_TEMPLATE (decl)) + || !DECL_LANG_SPECIFIC (not_tmpl) + || !DECL_MODULE_PURVIEW_P (not_tmpl) + || (!DECL_MODULE_IMPORT_P (not_tmpl) && header_module_p ()))); - if (TREE_CODE (decl) == TEMPLATE_DECL) - gcc_assert (!note_defs->find_slot (DECL_TEMPLATE_RESULT (decl), NO_INSERT)); + if (not_tmpl != decl) + gcc_assert (!note_defs->find_slot (not_tmpl, NO_INSERT)); #endif } @@ -5519,7 +5520,9 @@ trees_out::lang_decl_bools (tree t) WB (lang->u.base.concept_p); WB (lang->u.base.var_declared_inline_p); WB (lang->u.base.dependent_init_p); - WB (lang->u.base.module_purview_p); + /* When building a header unit, everthing is marked as purview, but + that's the GM purview, so not what the importer will mean */ + WB (lang->u.base.module_purview_p && !header_module_p ()); if (VAR_OR_FUNCTION_DECL_P (t)) WB (lang->u.base.module_attached_p); switch (lang->u.base.selector) @@ -11304,7 +11307,7 @@ trees_in::register_duplicate (tree decl, tree existing) /* We've read a definition of MAYBE_EXISTING. If not a duplicate, return MAYBE_EXISTING (into which the definition should be installed). Otherwise return NULL if already known bad, or the - duplicate we read (for ODR checking, or extracting addtional merge + duplicate we read (for ODR checking, or extracting additional merge information). */ tree -- cgit v1.1 From 2a26351b598242c2fbce95d2a0baacce0084aec6 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 2 Apr 2021 11:05:46 -0400 Subject: c++: lambda pack init-capture within generic lambda We represent the type of a pack init-capture as auto... with packs from the initializer stuck into PACK_EXPANSION_PARAMETER_PACKS so that expanding it produces the right number of elements. But when partially instantiating the auto..., we were changing PACK_EXPANSION_PARAMETER_PACKS to refer to only the auto itself. Fixed thus. gcc/cp/ChangeLog: PR c++/97938 * cp-tree.h (PACK_EXPANSION_AUTO_P): New. * lambda.c (add_capture): Set it. * pt.c (tsubst_pack_expansion): Handle it. gcc/testsuite/ChangeLog: PR c++/97938 * g++.dg/cpp2a/lambda-pack-init6.C: New test. --- gcc/cp/cp-tree.h | 4 ++++ gcc/cp/lambda.c | 7 +++++-- gcc/cp/pt.c | 19 +++++++++++++++---- 3 files changed, 24 insertions(+), 6 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 66bba7b..a5d9d7ac 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -481,6 +481,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; SWITCH_STMT_NO_BREAK_P (in SWITCH_STMT) LAMBDA_EXPR_CAPTURE_OPTIMIZED (in LAMBDA_EXPR) IMPLICIT_CONV_EXPR_BRACED_INIT (in IMPLICIT_CONV_EXPR) + PACK_EXPANSION_AUTO_P (in *_PACK_EXPANSION) 3: IMPLICIT_RVALUE_P (in NON_LVALUE_EXPR or STATIC_CAST_EXPR) ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -3855,6 +3856,9 @@ struct GTY(()) lang_decl { /* True iff this pack expansion is for sizeof.... */ #define PACK_EXPANSION_SIZEOF_P(NODE) TREE_LANG_FLAG_1 (NODE) +/* True iff this pack expansion is for auto... in lambda init-capture. */ +#define PACK_EXPANSION_AUTO_P(NODE) TREE_LANG_FLAG_2 (NODE) + /* True iff the wildcard can match a template parameter pack. */ #define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE) diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 421685c..b0fd6ec 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -606,8 +606,11 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p, parameter pack in this context. We will want as many fields as we have elements in the expansion of the initializer, so use its packs instead. */ - PACK_EXPANSION_PARAMETER_PACKS (type) - = uses_parameter_packs (initializer); + { + PACK_EXPANSION_PARAMETER_PACKS (type) + = uses_parameter_packs (initializer); + PACK_EXPANSION_AUTO_P (type) = true; + } } /* Make member variable. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7956e83..524a16a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13114,12 +13114,23 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, pattern and return a PACK_EXPANSION_*. The caller will need to deal with that. */ if (TREE_CODE (t) == EXPR_PACK_EXPANSION) - t = tsubst_expr (pattern, args, complain, in_decl, + result = tsubst_expr (pattern, args, complain, in_decl, /*integral_constant_expression_p=*/false); else - t = tsubst (pattern, args, complain, in_decl); - t = make_pack_expansion (t, complain); - return t; + result = tsubst (pattern, args, complain, in_decl); + result = make_pack_expansion (result, complain); + if (PACK_EXPANSION_AUTO_P (t)) + { + /* This is a fake auto... pack expansion created in add_capture with + _PACKS that don't appear in the pattern. Copy one over. */ + packs = PACK_EXPANSION_PARAMETER_PACKS (t); + pack = retrieve_local_specialization (TREE_VALUE (packs)); + gcc_checking_assert (DECL_PACK_P (pack)); + PACK_EXPANSION_PARAMETER_PACKS (result) + = build_tree_list (NULL_TREE, pack); + PACK_EXPANSION_AUTO_P (result) = true; + } + return result; } gcc_assert (len >= 0); -- 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') 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 260caabe10cde0158b87968a3bac85575301dafa Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 2 Apr 2021 19:46:24 -0400 Subject: c++: placeholder type constraint inside range-for [PR99869] In the testcase below, during ahead-of-time deduction of a constrained auto inside a range-based for loop, we trip over an assert within do_auto_deduction which expects the deduction context to be adc_return_type or adc_variable_type, but do_range_for_auto_deduction calls do_auto_deduction with the context defaulted to adc_unspecified. We could safely relax the assert to also accept adc_unspecified, but it seems the deduction context should really be adc_variable_type here. gcc/cp/ChangeLog: PR c++/99869 * parser.c (do_range_for_auto_deduction): Pass adc_variable_type to do_auto_deduction. gcc/testsuite/ChangeLog: PR c++/99869 * g++.dg/cpp2a/concepts-placeholder6.C: New test. --- gcc/cp/parser.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d0477c4..808e5b6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -12878,7 +12878,9 @@ do_range_for_auto_deduction (tree decl, tree range_expr) RO_UNARY_STAR, tf_warning_or_error); TREE_TYPE (decl) = do_auto_deduction (TREE_TYPE (decl), - iter_decl, auto_node); + iter_decl, auto_node, + tf_warning_or_error, + adc_variable_type); } } } -- cgit v1.1 From b7c1f3d66cfc171bc4e779068530101fb2f197f1 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 3 Apr 2021 00:16:28 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d0aa8a5..83240d2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,29 @@ +2021-04-02 Patrick Palka + + PR c++/99869 + * parser.c (do_range_for_auto_deduction): Pass adc_variable_type + to do_auto_deduction. + +2021-04-02 Patrick Palka + + PR c++/99586 + * semantics.c (finish_compound_literal): Check + template_placeholder_p instead of type_uses_auto. + +2021-04-02 Jason Merrill + + PR c++/97938 + * cp-tree.h (PACK_EXPANSION_AUTO_P): New. + * lambda.c (add_capture): Set it. + * pt.c (tsubst_pack_expansion): Handle it. + +2021-04-02 Nathan Sidwell + + * cp-tree.h (lang_decl_base): Correct module flag comment. + * module.cc (trees_in::assert_definition): Break out + not_tmpl var. + (trees_out::lang_decl_bools): Do not write purview for header units. + 2021-04-01 Marek Polacek PR c++/99831 -- cgit v1.1 From 23be03a0f243a084a0fe03d0b96a3d045e1a2b65 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 2 Apr 2021 14:49:15 -0400 Subject: c++: dependent attribute on parameter [PR97900] We were copying attributes from the template to the instantiation without considering that they might be dependent. To make sure that the new parms have the appropriate properties for the code pattern, let's just regenerate them. gcc/cp/ChangeLog: PR c++/97900 * pt.c (regenerate_decl_from_template): tsubst_decl the parms. gcc/testsuite/ChangeLog: PR c++/97900 * g++.dg/ext/vector40.C: New test. --- gcc/cp/pt.c | 71 ++++++++++--------------------------------------------------- 1 file changed, 11 insertions(+), 60 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 524a16a..68ee713 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -25364,8 +25364,6 @@ regenerate_decl_from_template (tree decl, tree tmpl, tree args) if (TREE_CODE (decl) == FUNCTION_DECL) { - tree decl_parm; - tree pattern_parm; tree specs; int args_depth; int parms_depth; @@ -25389,65 +25387,18 @@ regenerate_decl_from_template (tree decl, tree tmpl, tree args) } /* Merge parameter declarations. */ - decl_parm = skip_artificial_parms_for (decl, - DECL_ARGUMENTS (decl)); - pattern_parm - = skip_artificial_parms_for (code_pattern, - DECL_ARGUMENTS (code_pattern)); - while (decl_parm && !DECL_PACK_P (pattern_parm)) - { - tree parm_type; - tree attributes; - - if (DECL_NAME (decl_parm) != DECL_NAME (pattern_parm)) - DECL_NAME (decl_parm) = DECL_NAME (pattern_parm); - parm_type = tsubst (TREE_TYPE (pattern_parm), args, tf_error, - NULL_TREE); - parm_type = type_decays_to (parm_type); - if (!same_type_p (TREE_TYPE (decl_parm), parm_type)) - TREE_TYPE (decl_parm) = parm_type; - attributes = DECL_ATTRIBUTES (pattern_parm); - if (DECL_ATTRIBUTES (decl_parm) != attributes) - { - DECL_ATTRIBUTES (decl_parm) = attributes; - cplus_decl_attributes (&decl_parm, attributes, /*flags=*/0); - } - decl_parm = DECL_CHAIN (decl_parm); - pattern_parm = DECL_CHAIN (pattern_parm); + if (tree pattern_parm + = skip_artificial_parms_for (code_pattern, + DECL_ARGUMENTS (code_pattern))) + { + tree *p = &DECL_ARGUMENTS (decl); + for (int skip = num_artificial_parms_for (decl); skip; --skip) + p = &DECL_CHAIN (*p); + *p = tsubst_decl (pattern_parm, args, tf_error); + for (tree t = *p; t; t = DECL_CHAIN (t)) + DECL_CONTEXT (t) = decl; } - /* Merge any parameters that match with the function parameter - pack. */ - if (pattern_parm && DECL_PACK_P (pattern_parm)) - { - int i, len; - tree expanded_types; - /* Expand the TYPE_PACK_EXPANSION that provides the types for - the parameters in this function parameter pack. */ - expanded_types = tsubst_pack_expansion (TREE_TYPE (pattern_parm), - args, tf_error, NULL_TREE); - len = TREE_VEC_LENGTH (expanded_types); - for (i = 0; i < len; i++) - { - tree parm_type; - tree attributes; - - if (DECL_NAME (decl_parm) != DECL_NAME (pattern_parm)) - /* Rename the parameter to include the index. */ - DECL_NAME (decl_parm) = - make_ith_pack_parameter_name (DECL_NAME (pattern_parm), i); - parm_type = TREE_VEC_ELT (expanded_types, i); - parm_type = type_decays_to (parm_type); - if (!same_type_p (TREE_TYPE (decl_parm), parm_type)) - TREE_TYPE (decl_parm) = parm_type; - attributes = DECL_ATTRIBUTES (pattern_parm); - if (DECL_ATTRIBUTES (decl_parm) != attributes) - { - DECL_ATTRIBUTES (decl_parm) = attributes; - cplus_decl_attributes (&decl_parm, attributes, /*flags=*/0); - } - decl_parm = DECL_CHAIN (decl_parm); - } - } + /* Merge additional specifiers from the CODE_PATTERN. */ if (DECL_DECLARED_INLINE_P (code_pattern) && !DECL_DECLARED_INLINE_P (decl)) -- cgit v1.1 From 7c3ba2145ceddb0fd7f85fbf27f8db81896527d1 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 2 Apr 2021 17:07:12 -0400 Subject: c++: PMF template parm and noexcept [PR90664] The constexpr code only wants to preserve PTRMEM_CST in conversions if the conversions are only qualification conversions; dropping noexcept counts as a qualification adjustment in overload resolution, so let's include it here. gcc/cp/ChangeLog: PR c++/90664 * cvt.c (can_convert_qual): Check fnptr_conv_p. gcc/testsuite/ChangeLog: PR c++/90664 * g++.dg/cpp1z/noexcept-type24.C: New test. --- gcc/cp/cvt.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index d105113..f1687e8 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -2013,6 +2013,11 @@ can_convert_qual (tree type, tree expr) tree expr_type = TREE_TYPE (expr); gcc_assert (!same_type_p (type, expr_type)); + /* A function pointer conversion also counts as a Qualification Adjustment + under [over.ics.scs]. */ + if (fnptr_conv_p (type, expr_type)) + return true; + if (TYPE_PTR_P (type) && TYPE_PTR_P (expr_type)) return comp_ptr_ttypes (TREE_TYPE (type), TREE_TYPE (expr_type)); else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (expr_type)) -- cgit v1.1 From 04771106cda8dca2c8b975fd4648933679455b8f Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 3 Apr 2021 01:07:36 -0400 Subject: c++: NRV in lambda in template [PR91217] tsubst_lambda_expr was producing a function with two blocks that claimed to be the outermost block in the function body, one from the call to start_lambda_function in tsubst_lambda_expr, and one from tsubsting the block added by start_lambda_function when we first parsed the lambda. This messed with the named return value optimization, which only works for variables in the outermost block. gcc/cp/ChangeLog: PR c++/91217 * pt.c (tsubst_lambda_expr): Skip the body block from DECL_SAVED_TREE. gcc/testsuite/ChangeLog: PR c++/91217 * g++.dg/opt/nrv20.C: New test. --- gcc/cp/pt.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 68ee713..2763aa1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -19433,8 +19433,13 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) the purposes of template argument deduction. */ complain = tf_warning_or_error; - tsubst_expr (DECL_SAVED_TREE (oldfn), args, complain, r, - /*constexpr*/false); + tree saved = DECL_SAVED_TREE (oldfn); + if (TREE_CODE (saved) == BIND_EXPR && BIND_EXPR_BODY_BLOCK (saved)) + /* We already have a body block from start_lambda_function, we don't + need another to confuse NRV (91217). */ + saved = BIND_EXPR_BODY (saved); + + tsubst_expr (saved, args, complain, r, /*constexpr*/false); finish_lambda_function (body); -- cgit v1.1 From a809d8a737da1ccebcd93065fc57fc0f4d94894a Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 2 Apr 2021 17:11:32 -0400 Subject: c++: GC during late parsing collects live data [PR91416] Coming back to : This is a crash that points to a GC problem. Consider this test: __attribute__ ((unused)) struct S { S() { } } s; We're parsing a simple-declaration. While parsing the decl specs, we parse the attribute, which means creating a TREE_LIST using ggc_alloc_*. A function body is a complete-class context so when parsing the member-specification of this class-specifier, we parse the bodies of the functions we'd queued in cp_parser_late_parsing_for_member. This then leads to this call chain: cp_parser_function_definition_after_declarator -> expand_or_defer_fn -> expand_or_defer_fn_1 -> maybe_clone_body -> expand_or_defer_fn -> cgraph_node::finalize_function -> ggc_collect. In this test, the ggc_collect call collects the TREE_LIST we had allocated, and a crash duly ensues. I couldn't do what Richard suggested, that is, attach the attribute list to struct S, because we don't pass decl_specs from cp_parser_type_specifier down to cp_parser_class_specifier. Therefore I've attempted to do "push the decl_specifiers onto a vec that is a GC root", except I couldn't really push the decl_specifiers, because first I'd have to mark cp_decl_specifier_seq with GTY(()) and even that wouldn't be enough for me to be able to create static GTY(()) vec But here we only care about cp_decl_specifier_seq::attributes, so the patch is just this. I've also extended the test so now we test a nested class too. gcc/cp/ChangeLog: PR c++/91416 * parser.c: Create a GC root for attributes in a decl specifier. (cp_parser_type_specifier): Push/pop ->attributes onto/from it. gcc/testsuite/ChangeLog: PR c++/91416 * g++.dg/other/gc7.C: New test. --- gcc/cp/parser.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 808e5b6..c915d64 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18346,6 +18346,11 @@ cp_parser_explicit_specialization (cp_parser* parser) --parser->num_template_parameter_lists; } +/* Preserve the attributes across a garbage collect (by making it a GC + root), which can occur when parsing a member function. */ + +static GTY(()) vec *cp_parser_decl_specs_attrs; + /* Parse a type-specifier. type-specifier: @@ -18438,8 +18443,12 @@ cp_parser_type_specifier (cp_parser* parser, /* Parse tentatively so that we can back up if we don't find a class-specifier. */ cp_parser_parse_tentatively (parser); + if (decl_specs->attributes) + vec_safe_push (cp_parser_decl_specs_attrs, decl_specs->attributes); /* Look for the class-specifier. */ type_spec = cp_parser_class_specifier (parser); + if (decl_specs->attributes) + cp_parser_decl_specs_attrs->pop (); invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, type_spec); /* If that worked, we're done. */ if (cp_parser_parse_definitely (parser)) -- cgit v1.1 From c0756c4eb36b6bf4bf1ea0cf3633f08ae0e1c13d Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 4 Apr 2021 00:16:26 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 83240d2..2560796 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2021-04-03 Marek Polacek + + PR c++/91416 + * parser.c: Create a GC root for attributes in a decl specifier. + (cp_parser_type_specifier): Push/pop ->attributes onto/from it. + +2021-04-03 Jason Merrill + + PR c++/91217 + * pt.c (tsubst_lambda_expr): Skip the body block from + DECL_SAVED_TREE. + +2021-04-03 Jason Merrill + + PR c++/90664 + * cvt.c (can_convert_qual): Check fnptr_conv_p. + +2021-04-03 Jason Merrill + + PR c++/97900 + * pt.c (regenerate_decl_from_template): tsubst_decl + the parms. + 2021-04-02 Patrick Palka PR c++/99869 -- cgit v1.1 From c3d3bb0f03dbd02512ab46979088ee8e22520c24 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 3 Apr 2021 16:17:29 -0400 Subject: c++: array new initialized from a call [PR99643] Here the get_foo() call results in a TARGET_EXPR, which we strip in massage_init_elt, but then when build_vec_init tries to use it to initialize the array element we crash because build_aggr_init expects a class rvalue to have a TARGET_EXPR. So don't strip it. The stripping was added in r206639 for PR59659, so I checked that removing it didn't significantly increase compile time or memory usage for that testcase; compile time was unaffected, memory usage increased by 0.00004%. gcc/cp/ChangeLog: PR c++/99643 * typeck2.c (massage_init_elt): Don't strip TARGET_EXPR. gcc/testsuite/ChangeLog: PR c++/99643 * g++.dg/cpp0x/initlist-new5.C: New test. --- gcc/cp/typeck2.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index bde305b..a58d397 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1320,9 +1320,6 @@ massage_init_elt (tree type, tree init, int nested, int flags, if (flags & LOOKUP_AGGREGATE_PAREN_INIT) new_flags |= LOOKUP_AGGREGATE_PAREN_INIT; init = digest_init_r (type, init, nested ? 2 : 1, new_flags, complain); - /* Strip a simple TARGET_EXPR when we know this is an initializer. */ - if (SIMPLE_TARGET_EXPR_P (init)) - init = TARGET_EXPR_INITIAL (init); /* When we defer constant folding within a statement, we may want to defer this folding as well. */ tree t = fold_non_dependent_init (init, complain); -- cgit v1.1 From 914728849a35851ba1c1e2acfef2c44d2c9a6bc4 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Mon, 5 Apr 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2560796..62a38c1 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2021-04-04 Jason Merrill + + PR c++/99643 + * typeck2.c (massage_init_elt): Don't strip TARGET_EXPR. + 2021-04-03 Marek Polacek PR c++/91416 -- cgit v1.1 From a44a753a35542f86e82e198595ce3553f6d718f6 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 2 Apr 2021 05:45:02 -0400 Subject: c++: Fix print-tree for TEMPLATE_DECL The if allows TEMPLATE_DECL, but then checking DECL_MODULE_IMPORT_P crashes on TEMPLATE_DECL. Fixed by stripping TEMPLATE_DECL first. gcc/cp/ChangeLog: * ptree.c (cxx_print_decl): Check DECL_MODULE_IMPORT_P on template result. --- gcc/cp/ptree.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c index 95a4fdf..33b73fb 100644 --- a/gcc/cp/ptree.c +++ b/gcc/cp/ptree.c @@ -59,16 +59,16 @@ cxx_print_decl (FILE *file, tree node, int indent) bool need_indent = true; - if (TREE_CODE (node) == FUNCTION_DECL - || TREE_CODE (node) == VAR_DECL - || TREE_CODE (node) == TYPE_DECL - || TREE_CODE (node) == TEMPLATE_DECL - || TREE_CODE (node) == CONCEPT_DECL - || TREE_CODE (node) == NAMESPACE_DECL) + tree ntnode = STRIP_TEMPLATE (node); + if (TREE_CODE (ntnode) == FUNCTION_DECL + || TREE_CODE (ntnode) == VAR_DECL + || TREE_CODE (ntnode) == TYPE_DECL + || TREE_CODE (ntnode) == CONCEPT_DECL + || TREE_CODE (ntnode) == NAMESPACE_DECL) { unsigned m = 0; - if (DECL_LANG_SPECIFIC (node) && DECL_MODULE_IMPORT_P (node)) - m = get_importing_module (node, true); + if (DECL_LANG_SPECIFIC (ntnode) && DECL_MODULE_IMPORT_P (ntnode)) + m = get_importing_module (ntnode, true); if (const char *name = m == ~0u ? "" : module_name (m, true)) { @@ -78,7 +78,7 @@ cxx_print_decl (FILE *file, tree node, int indent) need_indent = false; } - if (DECL_LANG_SPECIFIC (node) && DECL_MODULE_PURVIEW_P (node)) + if (DECL_LANG_SPECIFIC (ntnode) && DECL_MODULE_PURVIEW_P (ntnode)) { if (need_indent) indent_to (file, indent + 3); -- cgit v1.1 From a99a7b0afe9a1f6f866e25b8572856ae8c1d3f8d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sun, 4 Apr 2021 01:01:56 -0400 Subject: c++: constexpr if and nested generic lambda [PR99201] When building up *_EXTRA_ARGS for a constexpr if or pack expansion, we need to walk into the body of a lambda to find all the local_specializations that we need to remember, like we do in find_parameter_packs_r. gcc/cp/ChangeLog: PR c++/99201 * pt.c (class el_data): Add visited field. (extract_local_specs): Pass it to cp_walk_tree. (extract_locals_r): Walk into the body of a lambda. gcc/testsuite/ChangeLog: PR c++/99201 * g++.dg/cpp1z/constexpr-if-lambda4.C: New test. --- gcc/cp/pt.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2763aa1..1d19a59 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12757,7 +12757,11 @@ tsubst_binary_right_fold (tree t, tree args, tsubst_flags_t complain, class el_data { public: + /* Set of variables declared within the pattern. */ hash_set internal; + /* Set of AST nodes that have been visited by the traversal. */ + hash_set visited; + /* List of local_specializations used within the pattern. */ tree extra; tsubst_flags_t complain; @@ -12777,6 +12781,15 @@ extract_locals_r (tree *tp, int */*walk_subtrees*/, void *data_) if (TREE_CODE (*tp) == DECL_EXPR) data.internal.add (DECL_EXPR_DECL (*tp)); + else if (TREE_CODE (*tp) == LAMBDA_EXPR) + { + /* Since we defer implicit capture, look in the parms and body. */ + tree fn = lambda_function (*tp); + cp_walk_tree (&TREE_TYPE (fn), &extract_locals_r, &data, + &data.visited); + cp_walk_tree (&DECL_SAVED_TREE (fn), &extract_locals_r, &data, + &data.visited); + } else if (tree spec = retrieve_local_specialization (*tp)) { if (data.internal.contains (*tp)) @@ -12833,7 +12846,7 @@ static tree extract_local_specs (tree pattern, tsubst_flags_t complain) { el_data data (complain); - cp_walk_tree_without_duplicates (&pattern, extract_locals_r, &data); + cp_walk_tree (&pattern, extract_locals_r, &data, &data.visited); return data.extra; } -- cgit v1.1 From bd89b8fe9efbdf0a95d827553d1a84fd3cefaa16 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sun, 4 Apr 2021 23:32:32 -0400 Subject: c++: extern template and static data member [PR99066] 'extern template' should mean that the relevant symbols are never emitted. But in this case we were assuming that DECL_EXTERNAL was already set on the variable, so we just needed to clear DECL_NOT_REALLY_EXTERN. Since DECL_EXTERNAL was not set, we emitted a definition of npos. gcc/cp/ChangeLog: PR c++/99066 * pt.c (mark_decl_instantiated): Set DECL_EXTERNAL. gcc/testsuite/ChangeLog: PR c++/99066 * g++.dg/cpp0x/extern_template-6.C: New test. --- gcc/cp/pt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1d19a59..396e622 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -24204,7 +24204,10 @@ mark_decl_instantiated (tree result, int extern_p) DECL_COMDAT (result) = 0; if (extern_p) - DECL_NOT_REALLY_EXTERN (result) = 0; + { + DECL_EXTERNAL (result) = 1; + DECL_NOT_REALLY_EXTERN (result) = 0; + } else { mark_definable (result); -- cgit v1.1 From dd6f588a7b8878d677af51ff4d1c1e3f9f6f40db Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 5 Apr 2021 07:51:28 -0700 Subject: c++: Unneeded export query [PR 99380] This problem got introduced fixing a module numbering problem. When preprocessing a header unit, we don't need to send an EXPORT query unless we're also determining dependencies, or the mapper asked us to. Sadly the testsuite isn't set up to test this kind of subtlety. I manually did that with stdin/stdout. PR c++/99380 gcc/cp/ * module.cc (name_pending_imports): Drop 'atend' parm. Don't query export when not needed. (preprocess_module, preprocessed_module): Adjust. --- gcc/cp/module.cc | 66 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 27 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index d5b7d28..c80c7bc 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -19262,15 +19262,11 @@ module_begin_main_file (cpp_reader *reader, line_maps *lmaps, filenames. */ static void -name_pending_imports (cpp_reader *reader, bool at_end) +name_pending_imports (cpp_reader *reader) { auto *mapper = get_mapper (cpp_main_loc (reader)); - bool only_headers = (flag_preprocess_only - && !bool (mapper->get_flags () & Cody::Flags::NameOnly) - && !cpp_get_deps (reader)); - if (at_end - && (!vec_safe_length (pending_imports) || only_headers)) + if (!vec_safe_length (pending_imports)) /* Not doing anything. */ return; @@ -19278,40 +19274,56 @@ name_pending_imports (cpp_reader *reader, bool at_end) auto n = dump.push (NULL); dump () && dump ("Resolving direct import names"); + bool want_deps = (bool (mapper->get_flags () & Cody::Flags::NameOnly) + || cpp_get_deps (reader)); + bool any = false; - mapper->Cork (); for (unsigned ix = 0; ix != pending_imports->length (); ix++) { module_state *module = (*pending_imports)[ix]; gcc_checking_assert (module->is_direct ()); - if (!module->filename - && !module->visited_p - && (module->is_header () || !only_headers)) + if (!module->filename && !module->visited_p) { - module->visited_p = true; - Cody::Flags flags = (flag_preprocess_only - ? Cody::Flags::None : Cody::Flags::NameOnly); + bool export_p = (module->module_p + && (module->is_partition () || module->exported_p)); - if (module->module_p - && (module->is_partition () || module->exported_p)) + Cody::Flags flags = Cody::Flags::None; + if (flag_preprocess_only + && !(module->is_header () && !export_p)) + { + if (!want_deps) + continue; + flags = Cody::Flags::NameOnly; + } + + if (!any) + { + any = true; + mapper->Cork (); + } + if (export_p) mapper->ModuleExport (module->get_flatname (), flags); else mapper->ModuleImport (module->get_flatname (), flags); + module->visited_p = true; } } - - auto response = mapper->Uncork (); - auto r_iter = response.begin (); - for (unsigned ix = 0; ix != pending_imports->length (); ix++) + + if (any) { - module_state *module = (*pending_imports)[ix]; - if (module->visited_p) + auto response = mapper->Uncork (); + auto r_iter = response.begin (); + for (unsigned ix = 0; ix != pending_imports->length (); ix++) { - module->visited_p = false; - gcc_checking_assert (!module->filename); + module_state *module = (*pending_imports)[ix]; + if (module->visited_p) + { + module->visited_p = false; + gcc_checking_assert (!module->filename); - module->set_filename (*r_iter); - ++r_iter; + module->set_filename (*r_iter); + ++r_iter; + } } } @@ -19384,7 +19396,7 @@ preprocess_module (module_state *module, location_t from_loc, unsigned n = dump.push (NULL); dump () && dump ("Reading %M preprocessor state", module); - name_pending_imports (reader, false); + name_pending_imports (reader); /* Preserve the state of the line-map. */ unsigned pre_hwm = LINEMAPS_ORDINARY_USED (line_table); @@ -19446,7 +19458,7 @@ preprocessed_module (cpp_reader *reader) dump () && dump ("Completed phase-4 (tokenization) processing"); - name_pending_imports (reader, true); + name_pending_imports (reader); vec_free (pending_imports); spans.maybe_init (); -- cgit v1.1 From 62d60246e53778db6ee613377dd013ba4b264968 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 5 Apr 2021 11:34:48 -0400 Subject: c++: lambda in DMI in class template [PR95870] Here enclosing_instantiation_of was failing to find a match because otctx is struct S and current_function_decl is S::S(), so the latter has more function contexts, and we end up trying to compare S() to NULL_TREE. After spending a bit of time working on establishing the correspondence in this case (class <=> constructor), it occurred to me that we could just use DECL_SOURCE_LOCATION, which is unique for lambdas, since they cannot be redeclared. Since we're so close to release, for now I'm only doing this for the case that was failing before. gcc/cp/ChangeLog: PR c++/95870 * pt.c (enclosing_instantiation_of): Compare DECL_SOURCE_LOCATION if there is no enclosing non-lambda function. gcc/testsuite/ChangeLog: PR c++/95870 * g++.dg/cpp0x/lambda/lambda-nsdmi10.C: New test. --- gcc/cp/pt.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 396e622..d6a8ede 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -14371,6 +14371,19 @@ enclosing_instantiation_of (tree otctx) || instantiated_lambda_fn_p (tctx)); tctx = decl_function_context (tctx)) ++lambda_count; + + if (!tctx) + { + /* Match using DECL_SOURCE_LOCATION, which is unique for all lambdas. + + For GCC 11 the above condition limits this to the previously failing + case where all enclosing functions are lambdas (95870). FIXME. */ + for (tree ofn = fn; ofn; ofn = decl_function_context (ofn)) + if (DECL_SOURCE_LOCATION (ofn) == DECL_SOURCE_LOCATION (otctx)) + return ofn; + gcc_unreachable (); + } + for (; fn; fn = decl_function_context (fn)) { tree ofn = fn; -- cgit v1.1 From 9f4c41147a41d08a74990eafe69a1064a3c13435 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 5 Apr 2021 14:26:03 -0400 Subject: c++: enum in generic lambda in template [PR95317] Here we weren't instantiating the enumerators because the arglist still had the template parameter for the generic lambda, so looking one up failed. We need to instantiate if the non-lambda enclosing scope is non-dependent. gcc/cp/ChangeLog: PR c++/95317 * pt.c (lookup_template_class_1): Do tsubst_enum when tsubsting a generic lambda. gcc/testsuite/ChangeLog: PR c++/95317 * g++.dg/cpp1y/lambda-generic-enum1.C: New test. --- gcc/cp/pt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d6a8ede..41bc633 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10173,7 +10173,8 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, = tree_cons (arglist, t, DECL_TEMPLATE_INSTANTIATIONS (found)); - if (TREE_CODE (template_type) == ENUMERAL_TYPE && !is_dependent_type + if (TREE_CODE (template_type) == ENUMERAL_TYPE + && !uses_template_parms (current_nonlambda_scope ()) && !DECL_ALIAS_TEMPLATE_P (gen_tmpl)) /* Now that the type has been registered on the instantiations list, we set up the enumerators. Because the enumeration -- cgit v1.1 From 07f56824fd4da14a48030e698c8eb58de951c741 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 5 Apr 2021 15:50:48 -0400 Subject: c++: reinterpret_cast from prvalue to rvalue ref [PR98440] In r260622 I allowed this under the general principle that [basic.lval] "Whenever a prvalue appears as an operand of an operator that expects a glvalue for that operand, the temporary materialization conversion (7.3.4) is applied to convert the expression to an xvalue." But [expr.reinterpret.cast] specifically excludes creating a temporary in this case. gcc/cp/ChangeLog: PR c++/98440 * typeck.c (build_reinterpret_cast_1): Don't perform temporary materialization. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/rv-cast6.C: Expect reinterpret_cast error. * g++.dg/cpp0x/reinterpret_cast2.C: Adjust message. * g++.old-deja/g++.jason/rvalue3.C: Likewise. --- gcc/cp/typeck.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index dff4e9b..8535ecc 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -7938,22 +7938,18 @@ build_reinterpret_cast_1 (location_t loc, tree type, tree expr, type = cv_unqualified (type); /* [expr.reinterpret.cast] - A glvalue expression of type T1 can be cast to the type + A glvalue of type T1, designating an object x, can be cast to the type "reference to T2" if an expression of type "pointer to T1" can be - explicitly converted to the type "pointer to T2" using a - reinterpret_cast. */ + explicitly converted to the type "pointer to T2" using a reinterpret_cast. + The result is that of *reinterpret_cast(p) where p is a pointer to x + of type "pointer to T1". No temporary is created, no copy is made, and no + constructors (11.4.4) or conversion functions (11.4.7) are called. */ if (TYPE_REF_P (type)) { - if (TYPE_REF_IS_RVALUE (type) && !VOID_TYPE_P (intype)) - { - if (!obvalue_p (expr)) - /* Perform the temporary materialization conversion. */ - expr = get_target_expr_sfinae (expr, complain); - } - else if (!lvalue_p (expr)) + if (!glvalue_p (expr)) { if (complain & tf_error) - error_at (loc, "invalid cast of an rvalue expression of type " + error_at (loc, "invalid cast of a prvalue expression of type " "%qT to type %qT", intype, type); return error_mark_node; -- cgit v1.1 From b07dd9b0d0e501a0083da79e2bca17041c007ec8 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 5 Apr 2021 16:22:51 -0400 Subject: c++: -Wunused, constant, and generic lambda [PR96311] We never called mark_use for a return value in a function with dependent return type. In that situation we don't know if the use is as an rvalue or lvalue, but we can use mark_exp_read instead. gcc/cp/ChangeLog: PR c++/96311 * typeck.c (check_return_expr): Call mark_exp_read in dependent case. gcc/testsuite/ChangeLog: PR c++/96311 * g++.dg/cpp1y/lambda-generic-Wunused.C: New test. --- gcc/cp/typeck.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 8535ecc..11dee7d 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -10215,6 +10215,9 @@ check_return_expr (tree retval, bool *no_warning) dependent: /* We should not have changed the return value. */ gcc_assert (retval == saved_retval); + /* We don't know if this is an lvalue or rvalue use, but + either way we can mark it as read. */ + mark_exp_read (retval); return retval; } -- cgit v1.1 From b1da991623341a2ecd97bf9034b93b0d63516517 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 6 Apr 2021 00:16:43 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 62a38c1..54bccc1 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,51 @@ +2021-04-05 Jason Merrill + + PR c++/96311 + * typeck.c (check_return_expr): Call mark_exp_read in dependent + case. + +2021-04-05 Jason Merrill + + PR c++/98440 + * typeck.c (build_reinterpret_cast_1): Don't perform + temporary materialization. + +2021-04-05 Jason Merrill + + PR c++/95317 + * pt.c (lookup_template_class_1): Do tsubst_enum when + tsubsting a generic lambda. + +2021-04-05 Jason Merrill + + PR c++/95870 + * pt.c (enclosing_instantiation_of): Compare DECL_SOURCE_LOCATION if + there is no enclosing non-lambda function. + +2021-04-05 Nathan Sidwell + + PR c++/99380 + * module.cc (name_pending_imports): Drop 'atend' parm. Don't + query export when not needed. + (preprocess_module, preprocessed_module): Adjust. + +2021-04-05 Jason Merrill + + PR c++/99066 + * pt.c (mark_decl_instantiated): Set DECL_EXTERNAL. + +2021-04-05 Jason Merrill + + PR c++/99201 + * pt.c (class el_data): Add visited field. + (extract_local_specs): Pass it to cp_walk_tree. + (extract_locals_r): Walk into the body of a lambda. + +2021-04-05 Jason Merrill + + * ptree.c (cxx_print_decl): Check DECL_MODULE_IMPORT_P on + template result. + 2021-04-04 Jason Merrill PR c++/99643 -- cgit v1.1 From 66de517b1c1dd22df7914f8e9a083cd5a73adbe2 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 5 Apr 2021 23:35:56 -0400 Subject: c++: placeholder type constraint in structured binding [PR99899] In this PR, we're crashing because the constraint handling inside do_auto_deduction doesn't expect to see an adc_decomp_type context. This patch fixes this by treating adc_decomp_type like adc_variable_type or adc_return_type during placeholder type constraint checking. Meanwhile, I noticed we weren't checking constraints at all when binding an array via a structured binding, since do_auto_deduction would exit early and bypass the constraint check. This patch fixes this by replacing the early exit with an appropriate setup of the 'targs' vector. gcc/cp/ChangeLog: PR c++/99899 * pt.c (do_auto_deduction): Don't exit early when deducing the array type of a structured binding. Also handle adc_decomp_type during constraint checking. gcc/testsuite/ChangeLog: PR c++/99899 * g++.dg/cpp2a/concepts-placeholder7.C: New test. * g++.dg/cpp2a/concepts-placeholder8.C: New test. --- gcc/cp/pt.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 41bc633..a08d08d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -29455,8 +29455,6 @@ do_auto_deduction (tree type, tree init, tree auto_node, tsubst_flags_t complain, auto_deduction_context context, tree outer_targs, int flags) { - tree targs; - if (init == error_mark_node) return error_mark_node; @@ -29520,14 +29518,17 @@ do_auto_deduction (tree type, tree init, tree auto_node, else init = resolve_nondeduced_context (init, complain); + tree targs; if (context == adc_decomp_type && auto_node == type && init != error_mark_node && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE) - /* [dcl.decomp]/1 - if decomposition declaration has no ref-qualifiers - and initializer has array type, deduce cv-qualified array type. */ - return cp_build_qualified_type_real (TREE_TYPE (init), TYPE_QUALS (type), - complain); + { + /* [dcl.struct.bind]/1 - if decomposition declaration has no ref-qualifiers + and initializer has array type, deduce cv-qualified array type. */ + targs = make_tree_vec (1); + TREE_VEC_ELT (targs, 0) = TREE_TYPE (init); + } else if (AUTO_IS_DECLTYPE (auto_node)) { tree stripped_init = tree_strip_any_location_wrapper (init); @@ -29613,7 +29614,8 @@ do_auto_deduction (tree type, tree init, tree auto_node, if (processing_template_decl) { gcc_checking_assert (context == adc_variable_type - || context == adc_return_type); + || context == adc_return_type + || context == adc_decomp_type); gcc_checking_assert (!type_dependent_expression_p (init)); /* If the constraint is dependent, we need to wait until instantiation time to resolve the placeholder. */ @@ -29621,7 +29623,9 @@ do_auto_deduction (tree type, tree init, tree auto_node, return type; } - if ((context == adc_return_type || context == adc_variable_type) + if ((context == adc_return_type + || context == adc_variable_type + || context == adc_decomp_type) && current_function_decl && DECL_TEMPLATE_INFO (current_function_decl)) outer_targs = DECL_TI_ARGS (current_function_decl); -- cgit v1.1 From 55f40d968b0bd3be4478a9481e829a99ee0fa04f Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 5 Apr 2021 22:50:44 -0400 Subject: c++: mangling of lambdas in default args [PR91241] In this testcase, the parms remembered in LAMBDA_EXPR_EXTRA_SCOPE are no longer the parms of the FUNCTION_DECL they have as their DECL_CONTEXT, so we were mangling both lambdas as parm #0. But since the parms are numbered from right to left we don't need to need to find them in the FUNCTION_DECL, we can measure their own DECL_CHAIN. gcc/cp/ChangeLog: PR c++/91241 * mangle.c (write_compact_number): Add sanity check. (write_local_name): Use list_length for parm number. gcc/testsuite/ChangeLog: PR c++/91241 * g++.dg/abi/lambda-defarg1.C: New test. --- gcc/cp/mangle.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 6c11134..4399165 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1628,6 +1628,7 @@ write_literal_operator_name (tree identifier) static void write_compact_number (int num) { + gcc_checking_assert (num >= 0); if (num > 0) write_unsigned_number (num - 1); write_char ('_'); @@ -2027,15 +2028,7 @@ write_local_name (tree function, const tree local_entity, /* For this purpose, parameters are numbered from right-to-left. */ if (parm) { - tree t; - int i = 0; - for (t = DECL_ARGUMENTS (function); t; t = DECL_CHAIN (t)) - { - if (t == parm) - i = 1; - else if (i) - ++i; - } + int i = list_length (parm); write_char ('d'); write_compact_number (i - 1); } -- cgit v1.1 From 8685348075d91945066dea9b564bd42cbc1d22bd Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 6 Apr 2021 01:21:05 -0400 Subject: c++: C++17 constexpr static data member linkage [PR99901] C++17 makes constexpr static data members implicitly inline variables. In C++14, a subsequent out-of-class declaration is the definition. We want to continue emitting a symbol for such a declaration in C++17 mode, for ABI compatibility with C++14 code that wants to refer to it. Normally I'd distinguish in- and out-of-class declarations by looking at DECL_IN_AGGR_P, but we never set DECL_IN_AGGR_P on inline variables. I think that's wrong, but don't want to mess with it so close to release. Conveniently, we already have a test for in-class declaration earlier in the function. gcc/cp/ChangeLog: PR c++/99901 * decl.c (cp_finish_decl): mark_needed an implicitly inline static data member with an out-of-class redeclaration. gcc/testsuite/ChangeLog: PR c++/99901 * g++.dg/cpp1z/inline-var9.C: New test. --- gcc/cp/decl.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6789aa8..edab147 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7693,10 +7693,13 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, if (asmspec_tree && asmspec_tree != error_mark_node) asmspec = TREE_STRING_POINTER (asmspec_tree); - if (current_class_type - && CP_DECL_CONTEXT (decl) == current_class_type - && TYPE_BEING_DEFINED (current_class_type) - && !CLASSTYPE_TEMPLATE_INSTANTIATION (current_class_type) + bool in_class_decl + = (current_class_type + && CP_DECL_CONTEXT (decl) == current_class_type + && TYPE_BEING_DEFINED (current_class_type) + && !CLASSTYPE_TEMPLATE_INSTANTIATION (current_class_type)); + + if (in_class_decl && (DECL_INITIAL (decl) || init)) DECL_INITIALIZED_IN_CLASS_P (decl) = 1; @@ -8069,6 +8072,13 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, if (!flag_weak) /* Check again now that we have an initializer. */ maybe_commonize_var (decl); + /* A class-scope constexpr variable with an out-of-class declaration. + C++17 makes them implicitly inline, but still force it out. */ + if (DECL_INLINE_VAR_P (decl) + && !DECL_VAR_DECLARED_INLINE_P (decl) + && !DECL_TEMPLATE_INSTANTIATION (decl) + && !in_class_decl) + mark_needed (decl); } if (var_definition_p -- cgit v1.1 From de03b82f3ca9103eba3699d1dc91b1d0ee1f16cb Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 6 Apr 2021 15:13:02 -0400 Subject: c++: access checking in aggregate initialization [PR96673] We were deferring access checks while parsing B{}, didn't adjust that when we went to instantiate the default member initializer for B::c, deferred access checking for C::C, and then checked it after parsing B{}, back in the main() context which has no access. We need to do the access checks in the class context of the DMI. I tried fixing this in push_to/pop_from_top_level, but that caused several regressions. gcc/cp/ChangeLog: PR c++/96673 * init.c (get_nsdmi): Don't defer access checking. gcc/testsuite/ChangeLog: PR c++/96673 * g++.dg/cpp1y/nsdmi-aggr13.C: New test. --- gcc/cp/init.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 7d598f6..91b45a1 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -591,6 +591,7 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain) { push_to_top_level (); push_nested_class (ctx); + push_deferring_access_checks (dk_no_deferred); pushed = true; } @@ -616,6 +617,7 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain) if (pushed) { + pop_deferring_access_checks (); pop_nested_class (); pop_from_top_level (); } -- cgit v1.1 From 8cac6af6f8ba5cce69161459e572e59c2be60e75 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 7 Apr 2021 00:16:39 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 54bccc1..06cd140 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,27 @@ +2021-04-06 Jason Merrill + + PR c++/96673 + * init.c (get_nsdmi): Don't defer access checking. + +2021-04-06 Jason Merrill + + PR c++/99901 + * decl.c (cp_finish_decl): mark_needed an implicitly inline + static data member with an out-of-class redeclaration. + +2021-04-06 Jason Merrill + + PR c++/91241 + * mangle.c (write_compact_number): Add sanity check. + (write_local_name): Use list_length for parm number. + +2021-04-06 Patrick Palka + + PR c++/99899 + * pt.c (do_auto_deduction): Don't exit early when deducing the + array type of a structured binding. Also handle adc_decomp_type + during constraint checking. + 2021-04-05 Jason Merrill PR c++/96311 -- cgit v1.1 From a528594cf9a74e5a0fbac13ef673064ed73e1b89 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 7 Apr 2021 14:55:48 -0400 Subject: c++: using overloaded with local decl [PR92918] The problem here was that the lookup for 'impl' when parsing the template only found the using-declaration, not the member function declaration. This happened because when trying to add the member function declaration, push_class_level_binding_1 saw that the current binding was a USING_DECL and the new value is an overload, and decided to just return success. That 'return true' dates back to r69921. In https://gcc.gnu.org/pipermail/gcc-patches/2003-July/110632.html Nathan mentions that we only push dependent USING_DECLs, which is no longer the case; now that we retain more USING_DECLs, handling this case like the other overloaded function cases seems like the obvious solution. gcc/cp/ChangeLog: PR c++/92918 * name-lookup.c (push_class_level_binding_1): Do overload a new function with a previous using-declaration. gcc/testsuite/ChangeLog: PR c++/92918 * g++.dg/lookup/using66.C: New test. --- gcc/cp/name-lookup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 3bce3d5..4e84e2f 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -5520,7 +5520,7 @@ push_class_level_binding_1 (tree name, tree x) old_decl = bval; else if (TREE_CODE (bval) == USING_DECL && OVL_P (target_decl)) - return true; + old_decl = bval; else if (OVL_P (target_decl) && OVL_P (target_bval)) old_decl = bval; -- cgit v1.1 From b40d45cb1930e9aa8a1f9a6a8728fd47ebeeaaac Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 7 Apr 2021 15:38:07 -0400 Subject: c++: base template friend [PR52625] Here we were mistakenly treating the injected-class-name as a partial specialization. gcc/cp/ChangeLog: PR c++/52625 * pt.c (maybe_process_partial_specialization): Check DECL_SELF_REFERENCE_P. gcc/testsuite/ChangeLog: PR c++/52625 * g++.dg/template/friend70.C: New test. --- gcc/cp/pt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a08d08d..dee8021 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -984,6 +984,10 @@ maybe_process_partial_specialization (tree type) if (CLASS_TYPE_P (type) && CLASSTYPE_LAMBDA_EXPR (type)) return type; + /* An injected-class-name is not a specialization. */ + if (DECL_SELF_REFERENCE_P (TYPE_NAME (type))) + return type; + if (TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM) { error ("name of class shadows template template parameter %qD", -- cgit v1.1 From fb5ed6d8c90a4bf8e677a3ff9bd79d83636ccff9 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 7 Apr 2021 16:42:44 -0400 Subject: c++: friend with redundant qualification [PR41723] Different code paths were correctly choosing to look up D directly, since C is the current instantiation, but here we decided to try to make it a typename type, leading to confusion. Fixed by using dependent_scope_p as we do elsewhere. gcc/cp/ChangeLog: PR c++/41723 * parser.c (cp_parser_class_name): Check dependent_scope_p. gcc/testsuite/ChangeLog: PR c++/41723 * g++.dg/template/friend71.C: New test. --- gcc/cp/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c915d64..59adac4 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -24639,7 +24639,7 @@ cp_parser_class_name (cp_parser *parser, const bool typename_p = (typename_keyword_p && parser->scope && TYPE_P (parser->scope) - && dependent_type_p (parser->scope)); + && dependent_scope_p (parser->scope)); /* Handle the common case (an identifier, but not a template-id) efficiently. */ if (token->type == CPP_NAME -- cgit v1.1 From 299859c2a458062c882c68c2e24022497726408f Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 8 Apr 2021 00:16:44 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 06cd140..3459697 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,20 @@ +2021-04-07 Jason Merrill + + PR c++/41723 + * parser.c (cp_parser_class_name): Check dependent_scope_p. + +2021-04-07 Jason Merrill + + PR c++/52625 + * pt.c (maybe_process_partial_specialization): Check + DECL_SELF_REFERENCE_P. + +2021-04-07 Jason Merrill + + PR c++/92918 + * name-lookup.c (push_class_level_binding_1): Do overload a new + function with a previous using-declaration. + 2021-04-06 Jason Merrill PR c++/96673 -- cgit v1.1 From 2cd5333d16419f596d07a830bb3f1c40fa8a7b5c Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 7 Apr 2021 16:44:24 -0400 Subject: c++: Fix ICE with unexpanded parameter pack [PR99844] In explicit17.C, we weren't detecting an unexpanded parameter pack in explicit(bool), so we crashed on a TEMPLATE_PARM_INDEX in constexpr. I noticed the same is true for noexcept(), but only since my patch to implement delayed parsing of noexcept. Previously, we would detect the unexpanded pack in push_template_decl but now the noexcept expression has not yet been parsed, so we need to do it a bit later. gcc/cp/ChangeLog: PR c++/99844 * decl.c (build_explicit_specifier): Call check_for_bare_parameter_packs. * except.c (build_noexcept_spec): Likewise. gcc/testsuite/ChangeLog: PR c++/99844 * g++.dg/cpp2a/explicit16.C: Use c++20. * g++.dg/cpp0x/noexcept66.C: New test. * g++.dg/cpp2a/explicit17.C: New test. --- gcc/cp/decl.c | 3 +++ gcc/cp/except.c | 2 ++ 2 files changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index edab147..3294b4f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -17991,6 +17991,9 @@ require_deduced_type (tree decl, tsubst_flags_t complain) tree build_explicit_specifier (tree expr, tsubst_flags_t complain) { + if (check_for_bare_parameter_packs (expr)) + return error_mark_node; + if (instantiation_dependent_expression_p (expr)) /* Wait for instantiation, tsubst_function_decl will handle it. */ return expr; diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 0bbc229..cbafc09 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1228,6 +1228,8 @@ type_throw_all_p (const_tree type) tree build_noexcept_spec (tree expr, tsubst_flags_t complain) { + if (check_for_bare_parameter_packs (expr)) + return error_mark_node; if (TREE_CODE (expr) != DEFERRED_NOEXCEPT && !value_dependent_expression_p (expr)) { -- cgit v1.1 From ac24fa46e449fbff0ff571951cfcc78b8488f6e7 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 8 Apr 2021 01:03:28 -0400 Subject: c++: improve specialization mismatch diagnostic [PR94529] We were telling users they needed more template<> to specialize a member template in a testcase with no member templates. Only produce that message if we actually see a member template, and also always print the candidates. gcc/cp/ChangeLog: PR c++/94529 * pt.c (determine_specialization): Improve diagnostic. gcc/testsuite/ChangeLog: PR c++/94529 * g++.dg/template/mem-spec2.C: New test. --- gcc/cp/pt.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index dee8021..46b237f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2201,6 +2201,7 @@ determine_specialization (tree template_id, ++header_count; tree orig_fns = fns; + bool header_mismatch = false; if (variable_template_p (fns)) { @@ -2248,7 +2249,10 @@ determine_specialization (tree template_id, specialization but rather a template instantiation, so there is no check we can perform here. */ if (header_count && header_count != template_count + 1) - continue; + { + header_mismatch = true; + continue; + } /* Check that the number of template arguments at the innermost level for DECL is the same as for FN. */ @@ -2482,13 +2486,12 @@ determine_specialization (tree template_id, { error ("template-id %qD for %q+D does not match any template " "declaration", template_id, decl); - if (header_count && header_count != template_count + 1) + if (header_mismatch) inform (DECL_SOURCE_LOCATION (decl), "saw %d %%>, need %d for " "specializing a member function template", header_count, template_count + 1); - else - print_candidates (orig_fns); + print_candidates (orig_fns); return error_mark_node; } else if ((templates && TREE_CHAIN (templates)) -- cgit v1.1 From 559d2f1e0eafd96c19dc5324db1a466286c0e7fc Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 8 Apr 2021 17:15:39 +0200 Subject: c++: Don't cache constexpr functions which are passed pointers to heap or static vars being constructed [PR99859] When cxx_bind_parameters_in_call is called e.g. on a method on an automatic variable, we evaluate the argument and because ADDR_EXPR of an automatic decl is not TREE_CONSTANT, we set *non_constant_args and don't cache it. But when it is called on an object located on the heap (allocated using C++20 constexpr new) where we represent it as TREE_STATIC artificial var, or when it is called on a static var that is currently being constructed, such ADDR_EXPRs are TREE_CONSTANT and we happily cache such calls, but they can in those cases have side-effects in the heap or static var objects and so caching them means such side-effects will happen only once and not as many times as that method or function is called. Furthermore, as Patrick mentioned in the PR, the argument doesn't need to be just ADDR_EXPR of the heap or static var or its components, but it could be a CONSTRUCTOR that has the ADDR_EXPR embedded anywhere. And the incorrectly cached function doesn't need to modify the pointed vars or their components, but some caller could be changing them in between the call that was cached and the call that used the cached result. The following patch fixes it by setting *non_constant_args also when the argument contains somewhere such an ADDR_EXPR, either of a heap artificial var or component thereof, or of a static var currently being constructed (where for that it uses the same check as cxx_eval_store_expression, ctx->global->values.get (...); addresses of other static variables would be rejected by cxx_eval_store_expression and therefore it is ok to cache such calls). 2021-04-08 Jakub Jelinek PR c++/99859 * constexpr.c (addr_of_non_const_var): New function. (cxx_bind_parameters_in_call): Set *non_constant_args to true even if cp_walk_tree on arg with addr_of_non_const_var callback returns true. * g++.dg/cpp1y/constexpr-99859-1.C: New test. * g++.dg/cpp1y/constexpr-99859-2.C: New test. * g++.dg/cpp2a/constexpr-new18.C: New test. * g++.dg/cpp2a/constexpr-new19.C: New test. --- gcc/cp/constexpr.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 42d00ec..c8d9dae 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1555,6 +1555,32 @@ free_constructor (tree t) } } +/* Helper function of cxx_bind_parameters_in_call. Return non-NULL + if *TP is address of a static variable (or part of it) currently being + constructed or of a heap artificial variable. */ + +static tree +addr_of_non_const_var (tree *tp, int *walk_subtrees, void *data) +{ + if (TREE_CODE (*tp) == ADDR_EXPR) + if (tree var = get_base_address (TREE_OPERAND (*tp, 0))) + if (VAR_P (var) && TREE_STATIC (var)) + { + if (DECL_NAME (var) == heap_uninit_identifier + || DECL_NAME (var) == heap_identifier + || DECL_NAME (var) == heap_vec_uninit_identifier + || DECL_NAME (var) == heap_vec_identifier) + return var; + + constexpr_global_ctx *global = (constexpr_global_ctx *) data; + if (global->values.get (var)) + return var; + } + if (TYPE_P (*tp)) + *walk_subtrees = false; + return NULL_TREE; +} + /* Subroutine of cxx_eval_call_expression. We are processing a call expression (either CALL_EXPR or AGGR_INIT_EXPR) in the context of CTX. Evaluate @@ -1616,6 +1642,15 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, /* The destructor needs to see any modifications the callee makes to the argument. */ *non_constant_args = true; + /* If arg is or contains address of a heap artificial variable or + of a static variable being constructed, avoid caching the + function call, as those variables might be modified by the + function, or might be modified by the callers in between + the cached function and just read by the function. */ + else if (!*non_constant_args + && cp_walk_tree (&arg, addr_of_non_const_var, ctx->global, + NULL)) + *non_constant_args = true; /* For virtual calls, adjust the this argument, so that it is the object on which the method is called, rather than -- cgit v1.1 From 9f74f9cf47ed9d65e65a06378041e9dd5698e49d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 8 Apr 2021 08:23:17 -0400 Subject: c++: improve reference binding diagnostic [PR91849] Here we were complaining about binding the lvalue reference to the rvalue result of converting from float to int, but didn't mention that conversion. Talk about the type of the initializer instead. gcc/cp/ChangeLog: PR c++/91849 * call.c (convert_like_internal): Improve reference diagnostic. gcc/testsuite/ChangeLog: PR c++/91849 * g++.dg/conversion/pr66211.C: Adjust diagnostic. * g++.dg/conversion/ref7.C: New test. --- gcc/cp/call.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4b81d0f..c9a8c0d 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -7898,8 +7898,19 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, "lvalue of type %qI", totype, extype); else if (!TYPE_REF_IS_RVALUE (ref_type) && !lvalue_p (expr) && !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type))) - error_at (loc, "cannot bind non-const lvalue reference of " - "type %qH to an rvalue of type %qI", totype, extype); + { + conversion *next = next_conversion (convs); + if (next->kind == ck_std) + { + next = next_conversion (next); + error_at (loc, "cannot bind non-const lvalue reference of " + "type %qH to a value of type %qI", + totype, next->type); + } + else + error_at (loc, "cannot bind non-const lvalue reference of " + "type %qH to an rvalue of type %qI", totype, extype); + } else if (!reference_compatible_p (TREE_TYPE (totype), extype)) { /* If we're converting from T[] to T[N], don't talk -- cgit v1.1 From 05708d6eef87a3dd0c68b1aed7f8d9c3824062b8 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 8 Apr 2021 13:07:37 -0400 Subject: c++: constrained CTAD for nested class template [PR97679] In the testcase below, we're crashing during constraint checking of the implicitly generated deduction guides for the nested class template A::B because we never substitute the outer template arguments (for A) into the constraint, neither ahead of time nor as part of satisfaction. Ideally we'd like to avoid substituting into a constraint ahead of time, but the "flattening" vector 'tsubst_args' is constructed under the assumption that all outer template arguments are already substituted in, and eliminating this assumption to yield a flattening vector that includes outer (generic) template arguments suitable for substituting into the constraint would be tricky and error-prone. So this patch takes the approximate approach of substituting the outer arguments into the constraint ahead of time, so that the subsequent substitution of 'tsubst_args' is coherent and so later satisfaction just works. gcc/cp/ChangeLog: PR c++/97679 * pt.c (build_deduction_guide): Document OUTER_ARGS. Substitute them into the propagated constraints. gcc/testsuite/ChangeLog: PR c++/97679 * g++.dg/cpp2a/concepts-ctad3.C: New test. --- gcc/cp/pt.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 46b237f..842a58c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -28602,7 +28602,8 @@ rewrite_tparm_list (tree oldelt, unsigned index, unsigned level, /* Returns a C++17 class deduction guide template based on the constructor CTOR. As a special case, CTOR can be a RECORD_TYPE for an implicit default guide, REFERENCE_TYPE for an implicit copy/move guide, or TREE_LIST for an - aggregate initialization guide. */ + aggregate initialization guide. OUTER_ARGS are the template arguments + for the enclosing scope of the class. */ static tree build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t complain) @@ -28728,7 +28729,15 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com if (fparms == error_mark_node) ok = false; if (ci) - ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor); + { + if (outer_args) + /* FIXME: We'd like to avoid substituting outer template + arguments into the constraint ahead of time, but the + construction of tsubst_args assumes that outer arguments + are already substituted in. */ + ci = tsubst_constraint_info (ci, outer_args, complain, ctor); + ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor); + } /* Parms are to have DECL_CHAIN tsubsted, which would be skipped if cp_unevaluated_operand. */ @@ -28744,7 +28753,12 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com fparms = tsubst_arg_types (fparms, targs, NULL_TREE, complain, ctor); fargs = tsubst (fargs, targs, complain, ctor); if (ci) - ci = tsubst_constraint_info (ci, targs, complain, ctor); + { + if (outer_args) + /* FIXME: As above. */ + ci = tsubst_constraint_info (ci, outer_args, complain, ctor); + ci = tsubst_constraint_info (ci, targs, complain, ctor); + } } --processing_template_decl; -- cgit v1.1 From 123b3e03c911a43054c1f88f5d3110e1d084dd4e Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 8 Apr 2021 13:07:43 -0400 Subject: c++: Don't substitute into constraints on lambdas [PR99874] We currently substitute through a lambda's constraints whenever we regenerate it via tsubst_lambda_expr. This is the wrong approach because it can lead to hard errors due to constraints being evaluated out of order (as in the testcase concepts-lambda17.C below), and because it doesn't mesh well with the recently added REQUIRES_EXPR_EXTRA_ARGS mechanism for delaying substitution into requires-expressions, which is the cause of this PR. But in order to avoid substituting through a lambda's constraints during regeneration, we need to be able to get at all in-scope template parameters and corresponding template arguments during constraint checking of a lambda's op(). And this information is not easily available when we need it, it seems. To that end, the approach that this patch takes is to add two new fields to LAMBDA_EXPR (and remove one): LAMBDA_EXPR_REGENERATED_FROM (replacing LAMBDA_EXPR_INSTANTIATED), and LAMBDA_EXPR_REGENERATING_TARGS. The former allows us to obtain the complete set of template parameters that are in-scope for a lambda's op(), and the latter gives us all outer template arguments that were used to regenerate the lambda (analogous to the TI_TEMPLATE and TI_ARGS of a TEMPLATE_INFO, respectively). LAMBDA_EXPR_REGENERATING_TARGS is not strictly necessary -- in an earlier prototype, I walked LAMBDA_EXPR_EXTRA_SCOPE to build up this set of outer template arguments on demand, but it seems cleaner to do it this way. (We'd need to walk LAMBDA_EXPR_EXTRA_SCOPE and not DECL/TYPE_CONTEXT because the latter skips over variable template scopes.) This patch also renames the predicate instantiated_lambda_fn_p to regenerated_lambda_fn_p, for sake of consistency with the rest of the patch which uses "regenerated" instead of "instantiated". gcc/cp/ChangeLog: PR c++/99874 * constraint.cc (get_normalized_constraints_from_decl): Handle regenerated lambdas. (satisfy_declaration_constraints): Likewise. Check for dependent args later. * cp-tree.h (LAMBDA_EXPR_INSTANTIATED): Replace with ... (LAMBDA_EXPR_REGENERATED_FROM): ... this. (LAMBDA_EXPR_REGENERATING_TARGS): New. (tree_lambda_expr::regenerated_from): New data member. (tree_lambda_expr::regenerating_targs): New data member. (add_to_template_args): Declare. (regenerated_lambda_fn_p): Likewise. (most_general_lambda): Likewise. * lambda.c (build_lambda_expr): Set LAMBDA_EXPR_REGENERATED_FROM and LAMBDA_EXPR_REGENERATING_TARGS. * pt.c (add_to_template_args): No longer static. (tsubst_function_decl): Unconditionally propagate constraints on the substituted function decl. (instantiated_lambda_fn_p): Rename to ... (regenerated_lambda_fn_p): ... this. Check LAMBDA_EXPR_REGENERATED_FROM instead of LAMBDA_EXPR_INSTANTIATED. (most_general_lambda): Define. (enclosing_instantiation_of): Adjust after renaming instantiated_lambda_fn_p. (tsubst_lambda_expr): Don't set LAMBDA_EXPR_INSTANTIATED. Set LAMBDA_EXPR_REGENERATED_FROM and LAMBDA_EXPR_REGENERATING_TARGS. Don't substitute or set constraints on the regenerated lambda. gcc/testsuite/ChangeLog: PR c++/99874 * g++.dg/cpp2a/concepts-lambda16.C: New test. * g++.dg/cpp2a/concepts-lambda17.C: New test. --- gcc/cp/constraint.cc | 43 ++++++++++++++++++++++++++++++++++++++----- gcc/cp/cp-tree.h | 20 +++++++++++++++----- gcc/cp/lambda.c | 2 ++ gcc/cp/pt.c | 42 ++++++++++++++++++++---------------------- 4 files changed, 75 insertions(+), 32 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 5cf43bd..0a9d1bf 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -886,6 +886,16 @@ get_normalized_constraints_from_decl (tree d, bool diag = false) it has the correct template information attached. */ d = strip_inheriting_ctors (d); + if (regenerated_lambda_fn_p (d)) + { + /* If this lambda was regenerated, DECL_TEMPLATE_PARMS doesn't contain + all in-scope template parameters, but the lambda from which it was + ultimately regenerated does, so use that instead. */ + tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (d)); + lambda = most_general_lambda (lambda); + d = lambda_function (lambda); + } + if (TREE_CODE (d) == TEMPLATE_DECL) { tmpl = d; @@ -3174,13 +3184,27 @@ satisfy_declaration_constraints (tree t, sat_info info) args = TI_ARGS (ti); if (inh_ctor_targs) args = add_outermost_template_args (args, inh_ctor_targs); + } - /* If any arguments depend on template parameters, we can't - check constraints. Pretend they're satisfied for now. */ - if (uses_template_parms (args)) - return boolean_true_node; + if (regenerated_lambda_fn_p (t)) + { + /* The TI_ARGS of a regenerated lambda contains only the innermost + set of template arguments. Augment this with the outer template + arguments that were used to regenerate the lambda. */ + gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1); + tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t)); + tree outer_args = LAMBDA_EXPR_REGENERATING_TARGS (lambda); + if (args) + args = add_to_template_args (outer_args, args); + else + args = outer_args; } + /* If any arguments depend on template parameters, we can't + check constraints. Pretend they're satisfied for now. */ + if (uses_template_parms (args)) + return boolean_true_node; + /* Get the normalized constraints. */ tree norm = get_normalized_constraints_from_decl (t, info.noisy ()); @@ -3227,7 +3251,16 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info) gcc_assert (TREE_CODE (t) == TEMPLATE_DECL); - args = add_outermost_template_args (t, args); + if (regenerated_lambda_fn_p (t)) + { + /* As in the two-parameter version of this function. */ + gcc_assert (TMPL_ARGS_DEPTH (args) == 1); + tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t)); + tree outer_args = LAMBDA_EXPR_REGENERATING_TARGS (lambda); + args = add_to_template_args (outer_args, args); + } + else + args = add_outermost_template_args (t, args); /* If any arguments depend on template parameters, we can't check constraints. Pretend they're satisfied for now. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a5d9d7ac..bf9d5ad 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -490,7 +490,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; DECLTYPE_FOR_REF_CAPTURE (in DECLTYPE_TYPE) CONSTRUCTOR_C99_COMPOUND_LITERAL (in CONSTRUCTOR) OVL_NESTED_P (in OVERLOAD) - LAMBDA_EXPR_INSTANTIATED (in LAMBDA_EXPR) DECL_MODULE_EXPORT_P (in _DECL) 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, @@ -1434,10 +1433,6 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \ TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE)) -/* True iff this LAMBDA_EXPR was generated in tsubst_lambda_expr. */ -#define LAMBDA_EXPR_INSTANTIATED(NODE) \ - TREE_LANG_FLAG_3 (LAMBDA_EXPR_CHECK (NODE)) - /* True if this TREE_LIST in LAMBDA_EXPR_CAPTURE_LIST is for an explicit capture. */ #define LAMBDA_CAPTURE_EXPLICIT_P(NODE) \ @@ -1461,6 +1456,16 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_PENDING_PROXIES(NODE) \ (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->pending_proxies) +/* The immediate LAMBDA_EXPR from which NODE was regenerated, or NULL_TREE + (if NODE was not regenerated via tsubst_lambda_expr). */ +#define LAMBDA_EXPR_REGENERATED_FROM(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regenerated_from) + +/* The full set of template arguments used to regenerate NODE, or NULL_TREE + (if NODE was not regenerated via tsubst_lambda_expr). */ +#define LAMBDA_EXPR_REGENERATING_TARGS(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regenerating_targs) + /* The closure type of the lambda, which is also the type of the LAMBDA_EXPR. */ #define LAMBDA_EXPR_CLOSURE(NODE) \ @@ -1472,6 +1477,8 @@ struct GTY (()) tree_lambda_expr tree capture_list; tree this_capture; tree extra_scope; + tree regenerated_from; + tree regenerating_targs; vec *pending_proxies; location_t locus; enum cp_lambda_default_capture_mode_type default_capture_mode : 8; @@ -7247,6 +7254,7 @@ extern unsigned get_mergeable_specialization_flags (tree tmpl, tree spec); extern void add_mergeable_specialization (bool is_decl, bool is_alias, spec_entry *, tree outer, unsigned); +extern tree add_to_template_args (tree, tree); extern tree add_outermost_template_args (tree, tree); extern tree add_extra_args (tree, tree); extern tree build_extra_args (tree, tree, tsubst_flags_t); @@ -7557,6 +7565,8 @@ extern void record_null_lambda_scope (tree); extern void finish_lambda_scope (void); extern tree start_lambda_function (tree fn, tree lambda_expr); extern void finish_lambda_function (tree body); +extern bool regenerated_lambda_fn_p (tree); +extern tree most_general_lambda (tree); /* in tree.c */ extern int cp_tree_operand_length (const_tree); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index b0fd6ec..c0a5ffb 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -41,6 +41,8 @@ build_lambda_expr (void) LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) = CPLD_NONE; LAMBDA_EXPR_CAPTURE_LIST (lambda) = NULL_TREE; LAMBDA_EXPR_THIS_CAPTURE (lambda) = NULL_TREE; + LAMBDA_EXPR_REGENERATED_FROM (lambda) = NULL_TREE; + LAMBDA_EXPR_REGENERATING_TARGS (lambda) = NULL_TREE; LAMBDA_EXPR_PENDING_PROXIES (lambda) = NULL; LAMBDA_EXPR_MUTABLE_P (lambda) = false; return lambda; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 842a58c..daf1b5a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -151,7 +151,6 @@ static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t, static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t, bool, bool); static void tsubst_enum (tree, tree, tree); -static tree add_to_template_args (tree, tree); static bool check_instantiated_args (tree, tree, tsubst_flags_t); static int check_non_deducible_conversion (tree, tree, int, int, struct conversion **, bool); @@ -553,7 +552,7 @@ maybe_end_member_template_processing (void) /* Return a new template argument vector which contains all of ARGS, but has as its innermost set of arguments the EXTRA_ARGS. */ -static tree +tree add_to_template_args (tree args, tree extra_args) { tree new_args; @@ -14065,10 +14064,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, don't substitute through the constraints; that's only done when they are checked. */ if (tree ci = get_constraints (t)) - /* Unless we're regenerating a lambda, in which case we'll set the - lambda's constraints in tsubst_lambda_expr. */ - if (!lambda_fntype) - set_constraints (r, ci); + set_constraints (r, ci); if (DECL_FRIEND_CONTEXT (t)) SET_DECL_FRIEND_CONTEXT (r, @@ -14354,13 +14350,24 @@ lambda_fn_in_template_p (tree fn) which the above is true. */ bool -instantiated_lambda_fn_p (tree fn) +regenerated_lambda_fn_p (tree fn) { if (!fn || !LAMBDA_FUNCTION_P (fn)) return false; tree closure = DECL_CONTEXT (fn); tree lam = CLASSTYPE_LAMBDA_EXPR (closure); - return LAMBDA_EXPR_INSTANTIATED (lam); + return LAMBDA_EXPR_REGENERATED_FROM (lam) != NULL_TREE; +} + +/* Return the LAMBDA_EXPR from which T was ultimately regenerated. + If T is not a regenerated LAMBDA_EXPR, return T. */ + +tree +most_general_lambda (tree t) +{ + while (LAMBDA_EXPR_REGENERATED_FROM (t)) + t = LAMBDA_EXPR_REGENERATED_FROM (t); + return t; } /* We're instantiating a variable from template function TCTX. Return the @@ -14376,7 +14383,7 @@ enclosing_instantiation_of (tree otctx) int lambda_count = 0; for (; tctx && (lambda_fn_in_template_p (tctx) - || instantiated_lambda_fn_p (tctx)); + || regenerated_lambda_fn_p (tctx)); tctx = decl_function_context (tctx)) ++lambda_count; @@ -14396,7 +14403,7 @@ enclosing_instantiation_of (tree otctx) { tree ofn = fn; int flambda_count = 0; - for (; fn && instantiated_lambda_fn_p (fn); + for (; fn && regenerated_lambda_fn_p (fn); fn = decl_function_context (fn)) ++flambda_count; if ((fn && DECL_TEMPLATE_INFO (fn)) @@ -19271,7 +19278,9 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r) = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t); LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t); - LAMBDA_EXPR_INSTANTIATED (r) = true; + LAMBDA_EXPR_REGENERATED_FROM (r) = t; + LAMBDA_EXPR_REGENERATING_TARGS (r) + = add_to_template_args (LAMBDA_EXPR_REGENERATING_TARGS (t), args); gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL); @@ -19413,17 +19422,6 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) finish_member_declaration (fn); } - if (tree ci = get_constraints (oldfn)) - { - /* Substitute into the lambda's constraints. */ - if (oldtmpl) - ++processing_template_decl; - ci = tsubst_constraint_info (ci, args, complain, in_decl); - if (oldtmpl) - --processing_template_decl; - set_constraints (fn, ci); - } - /* Let finish_function set this. */ DECL_DECLARED_CONSTEXPR_P (fn) = false; -- cgit v1.1 From 019a922063f26784d5a070d9198a1f937b8a8343 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 9 Apr 2021 00:16:56 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3459697..a3819b3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,65 @@ +2021-04-08 Patrick Palka + + PR c++/99874 + * constraint.cc (get_normalized_constraints_from_decl): Handle + regenerated lambdas. + (satisfy_declaration_constraints): Likewise. Check for + dependent args later. + * cp-tree.h (LAMBDA_EXPR_INSTANTIATED): Replace with ... + (LAMBDA_EXPR_REGENERATED_FROM): ... this. + (LAMBDA_EXPR_REGENERATING_TARGS): New. + (tree_lambda_expr::regenerated_from): New data member. + (tree_lambda_expr::regenerating_targs): New data member. + (add_to_template_args): Declare. + (regenerated_lambda_fn_p): Likewise. + (most_general_lambda): Likewise. + * lambda.c (build_lambda_expr): Set LAMBDA_EXPR_REGENERATED_FROM + and LAMBDA_EXPR_REGENERATING_TARGS. + * pt.c (add_to_template_args): No longer static. + (tsubst_function_decl): Unconditionally propagate constraints on + the substituted function decl. + (instantiated_lambda_fn_p): Rename to ... + (regenerated_lambda_fn_p): ... this. Check + LAMBDA_EXPR_REGENERATED_FROM instead of + LAMBDA_EXPR_INSTANTIATED. + (most_general_lambda): Define. + (enclosing_instantiation_of): Adjust after renaming + instantiated_lambda_fn_p. + (tsubst_lambda_expr): Don't set LAMBDA_EXPR_INSTANTIATED. Set + LAMBDA_EXPR_REGENERATED_FROM and LAMBDA_EXPR_REGENERATING_TARGS. + Don't substitute or set constraints on the regenerated lambda. + +2021-04-08 Patrick Palka + + PR c++/97679 + * pt.c (build_deduction_guide): Document OUTER_ARGS. Substitute + them into the propagated constraints. + +2021-04-08 Jason Merrill + + PR c++/91849 + * call.c (convert_like_internal): Improve reference diagnostic. + +2021-04-08 Jakub Jelinek + + PR c++/99859 + * constexpr.c (addr_of_non_const_var): New function. + (cxx_bind_parameters_in_call): Set *non_constant_args to true + even if cp_walk_tree on arg with addr_of_non_const_var callback + returns true. + +2021-04-08 Jason Merrill + + PR c++/94529 + * pt.c (determine_specialization): Improve diagnostic. + +2021-04-08 Marek Polacek + + PR c++/99844 + * decl.c (build_explicit_specifier): Call + check_for_bare_parameter_packs. + * except.c (build_noexcept_spec): Likewise. + 2021-04-07 Jason Merrill PR c++/41723 -- cgit v1.1 From 625dadaf5df5a2ae0d8c5660fd1eec8ba354479c Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 8 Apr 2021 14:39:28 -0400 Subject: c++: Fix two issues with auto function parameter [PR99806] When we have a member function with auto parameter like this: struct S { void f(auto); }; cp_parser_member_declaration -> grokfield produces a FUNCTION_DECL "void S::foo(auto:1)", and then finish_fully_implicit_template turns that FUNCTION_DECL into a TEMPLATE_DECL. The bug here is that we only call cp_parser_save_default_args for a FUNCTION_DECL. As a consequence, abbrev10.C is rejected because we complain that the default argument has not been defined, and abbrev11.C ICEs, because we don't re-parse the delayed noexcept, so the DEFERRED_PARSE tree leaks into tsubst* where we crash. This patch fixes both issues. gcc/cp/ChangeLog: PR c++/99806 * parser.c (cp_parser_member_declaration): Call cp_parser_save_default_args even for function templates. Use STRIP_TEMPLATE on the declaration we're passing. gcc/testsuite/ChangeLog: PR c++/99806 * g++.dg/concepts/abbrev10.C: New test. * g++.dg/concepts/abbrev11.C: New test. --- gcc/cp/parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 59adac4..e6e6ed7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -26433,8 +26433,8 @@ cp_parser_member_declaration (cp_parser* parser) || !DECL_DECLARES_FUNCTION_P (decl)) finish_member_declaration (decl); - if (TREE_CODE (decl) == FUNCTION_DECL) - cp_parser_save_default_args (parser, decl); + if (DECL_DECLARES_FUNCTION_P (decl)) + cp_parser_save_default_args (parser, STRIP_TEMPLATE (decl)); else if (TREE_CODE (decl) == FIELD_DECL && DECL_INITIAL (decl)) /* Add DECL to the queue of NSDMI to be parsed later. */ -- cgit v1.1 From b2576d75ed8900f77849ceacf7fe5f0f3abe734d Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 9 Apr 2021 17:03:04 -0400 Subject: c++: Use a TEMPLATE_INFO to hold regenerated-lambda info A TEMPLATE_INFO is a natural fit for what LAMBDA_EXPR_REGENERATED_FROM and LAMBDA_EXPR_REGENERATING_TARGS hold, so let's use it instead. gcc/cp/ChangeLog: * cp-tree.h (LAMBDA_EXPR_REGENERATED_FROM) (LAMBDA_EXPR_REGENERATING_TARGS): Replace these with ... (LAMBDA_EXPR_REGEN_INFO): ... this. (tree_lambda_expr::regenerated_from) (tree_lambda_expr::regenerating_targs): Replace these with ... (tree_lambda_expr::regen_info): ... this. * constraint.cc (satisfy_declaration_constraints): Adjust accordingly. * lambda.c (build_lambda_expr): Likewise. * pt.c (regenerated_lambda_fn_p): Likewise. (most_general_lambda): Likewise. (tsubst_lambda_expr): Likewise. --- gcc/cp/constraint.cc | 4 ++-- gcc/cp/cp-tree.h | 18 +++++++----------- gcc/cp/lambda.c | 3 +-- gcc/cp/pt.c | 15 +++++++++------ 4 files changed, 19 insertions(+), 21 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 0a9d1bf..0ddb299 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3193,7 +3193,7 @@ satisfy_declaration_constraints (tree t, sat_info info) arguments that were used to regenerate the lambda. */ gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1); tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t)); - tree outer_args = LAMBDA_EXPR_REGENERATING_TARGS (lambda); + tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda)); if (args) args = add_to_template_args (outer_args, args); else @@ -3256,7 +3256,7 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info) /* As in the two-parameter version of this function. */ gcc_assert (TMPL_ARGS_DEPTH (args) == 1); tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t)); - tree outer_args = LAMBDA_EXPR_REGENERATING_TARGS (lambda); + tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda)); args = add_to_template_args (outer_args, args); } else diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bf9d5ad..e42b82a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1456,15 +1456,12 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_PENDING_PROXIES(NODE) \ (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->pending_proxies) -/* The immediate LAMBDA_EXPR from which NODE was regenerated, or NULL_TREE - (if NODE was not regenerated via tsubst_lambda_expr). */ -#define LAMBDA_EXPR_REGENERATED_FROM(NODE) \ - (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regenerated_from) - -/* The full set of template arguments used to regenerate NODE, or NULL_TREE - (if NODE was not regenerated via tsubst_lambda_expr). */ -#define LAMBDA_EXPR_REGENERATING_TARGS(NODE) \ - (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regenerating_targs) +/* If NODE was regenerated via tsubst_lambda_expr, this is a TEMPLATE_INFO + whose TI_TEMPLATE is the immediate LAMBDA_EXPR from which NODE was + regenerated, and TI_ARGS is the full set of template arguments used + to regenerate NODE from the most general lambda. */ +#define LAMBDA_EXPR_REGEN_INFO(NODE) \ + (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->regen_info) /* The closure type of the lambda, which is also the type of the LAMBDA_EXPR. */ @@ -1477,8 +1474,7 @@ struct GTY (()) tree_lambda_expr tree capture_list; tree this_capture; tree extra_scope; - tree regenerated_from; - tree regenerating_targs; + tree regen_info; vec *pending_proxies; location_t locus; enum cp_lambda_default_capture_mode_type default_capture_mode : 8; diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index c0a5ffb..16e2b4c 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -41,8 +41,7 @@ build_lambda_expr (void) LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) = CPLD_NONE; LAMBDA_EXPR_CAPTURE_LIST (lambda) = NULL_TREE; LAMBDA_EXPR_THIS_CAPTURE (lambda) = NULL_TREE; - LAMBDA_EXPR_REGENERATED_FROM (lambda) = NULL_TREE; - LAMBDA_EXPR_REGENERATING_TARGS (lambda) = NULL_TREE; + LAMBDA_EXPR_REGEN_INFO (lambda) = NULL_TREE; LAMBDA_EXPR_PENDING_PROXIES (lambda) = NULL; LAMBDA_EXPR_MUTABLE_P (lambda) = false; return lambda; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index daf1b5a..01c807b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -14356,7 +14356,7 @@ regenerated_lambda_fn_p (tree fn) return false; tree closure = DECL_CONTEXT (fn); tree lam = CLASSTYPE_LAMBDA_EXPR (closure); - return LAMBDA_EXPR_REGENERATED_FROM (lam) != NULL_TREE; + return LAMBDA_EXPR_REGEN_INFO (lam) != NULL_TREE; } /* Return the LAMBDA_EXPR from which T was ultimately regenerated. @@ -14365,8 +14365,8 @@ regenerated_lambda_fn_p (tree fn) tree most_general_lambda (tree t) { - while (LAMBDA_EXPR_REGENERATED_FROM (t)) - t = LAMBDA_EXPR_REGENERATED_FROM (t); + while (tree ti = LAMBDA_EXPR_REGEN_INFO (t)) + t = TI_TEMPLATE (ti); return t; } @@ -19278,9 +19278,12 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r) = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t); LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t); - LAMBDA_EXPR_REGENERATED_FROM (r) = t; - LAMBDA_EXPR_REGENERATING_TARGS (r) - = add_to_template_args (LAMBDA_EXPR_REGENERATING_TARGS (t), args); + if (tree ti = LAMBDA_EXPR_REGEN_INFO (t)) + LAMBDA_EXPR_REGEN_INFO (r) + = build_template_info (t, add_to_template_args (TI_ARGS (ti), args)); + else + LAMBDA_EXPR_REGEN_INFO (r) + = build_template_info (t, args); gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL); -- cgit v1.1 From 3115aba8d856faadaab5c79bc4823a39ebc21bb2 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 10 Apr 2021 00:16:23 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a3819b3..5d35496 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,25 @@ +2021-04-09 Patrick Palka + + * cp-tree.h (LAMBDA_EXPR_REGENERATED_FROM) + (LAMBDA_EXPR_REGENERATING_TARGS): Replace these with ... + (LAMBDA_EXPR_REGEN_INFO): ... this. + (tree_lambda_expr::regenerated_from) + (tree_lambda_expr::regenerating_targs): Replace these with ... + (tree_lambda_expr::regen_info): ... this. + * constraint.cc (satisfy_declaration_constraints): Adjust + accordingly. + * lambda.c (build_lambda_expr): Likewise. + * pt.c (regenerated_lambda_fn_p): Likewise. + (most_general_lambda): Likewise. + (tsubst_lambda_expr): Likewise. + +2021-04-09 Marek Polacek + + PR c++/99806 + * parser.c (cp_parser_member_declaration): Call + cp_parser_save_default_args even for function templates. Use + STRIP_TEMPLATE on the declaration we're passing. + 2021-04-08 Patrick Palka PR c++/99874 -- cgit v1.1 From e89055f90cff9fb6f565b9374e1ab74f805682fb Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 9 Apr 2021 16:43:50 -0400 Subject: c++: pack in base-specifier in lambda [PR100006] Normally cp_parser_base_clause prevents unexpanded packs, but in a lambda check_for_bare_parameter_packs allows it. Then we weren't finding the pack when scanning the lambda body. This doesn't fix a valid variant like template void sink (Ts&&...); template void f() { sink ([] { struct S : Ts { }; }...); } int main() { f(); } but that's a much bigger project. gcc/cp/ChangeLog: PR c++/100006 * pt.c (find_parameter_packs_r) [TAG_DEFN]: Look into bases. gcc/testsuite/ChangeLog: PR c++/100006 * g++.dg/cpp0x/lambda/lambda-variadic13.C: New test. --- gcc/cp/pt.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 01c807b..b32833003 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -4061,6 +4061,15 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) *walk_subtrees = 0; return NULL_TREE; + case TAG_DEFN: + /* Local class, need to look through the whole definition. */ + t = TREE_TYPE (t); + if (CLASS_TYPE_P (t)) + for (tree bb : BINFO_BASE_BINFOS (TYPE_BINFO (t))) + cp_walk_tree (&BINFO_TYPE (bb), &find_parameter_packs_r, + ppd, ppd->visited); + return NULL_TREE; + default: return NULL_TREE; } -- cgit v1.1 From 1a19d334ce493ec2ce2daeac74beef63fd67e2bc Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 9 Apr 2021 18:02:38 -0400 Subject: c++: deduction guide using alias [PR99180] alias_ctad_tweaks was expecting that all deduction guides for the class would be suitable for deduction from the alias definition; in this case, the deduction guide uses 'true' and the alias B uses 'false', so deduction fails. But that's OK, we just don't use that deduction guide. I also noticed that we were giving up on deduction entirely if substitution failed for some guide; we should only give up on that particular deduction guide. We ought to give a better diagnostic about this case when deduction fails, but that can wait. gcc/cp/ChangeLog: PR c++/99180 PR c++/93295 PR c++/93867 PR c++/99118 PR c++/96873 * pt.c (alias_ctad_tweaks): Handle failure better. gcc/testsuite/ChangeLog: PR c++/99180 PR c++/93295 PR c++/93867 PR c++/95486 * g++.dg/cpp2a/class-deduction-alias5.C: New test. * g++.dg/cpp2a/class-deduction-alias6.C: New test. * g++.dg/cpp2a/class-deduction-alias7.C: New test. * g++.dg/cpp2a/class-deduction-alias8.C: New test. --- gcc/cp/pt.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b32833003..abd1ad4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -29042,7 +29042,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides) unsigned len = TREE_VEC_LENGTH (ftparms); tree targs = make_tree_vec (len); int err = unify (ftparms, targs, ret, utype, UNIFY_ALLOW_NONE, false); - gcc_assert (!err); + if (err) + continue; /* The number of parms for f' is the number of parms for A plus non-deduced parms of f. */ @@ -29075,7 +29076,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides) guideness, and explicit-specifier. */ tree g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain); if (g == error_mark_node) - return error_mark_node; + continue; DECL_USE_TEMPLATE (g) = 0; fprime = build_template_decl (g, gtparms, false); DECL_TEMPLATE_RESULT (fprime) = g; @@ -29089,7 +29090,7 @@ alias_ctad_tweaks (tree tmpl, tree uguides) if (ci) ci = tsubst_constraint_info (ci, targs, complain, in_decl); if (ci == error_mark_node) - return error_mark_node; + continue; /* Add a constraint that the return type matches the instantiation of A with the same template arguments. */ -- cgit v1.1 From 82198676c80764ca7cf05f891afaee83b9179dd1 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 10 Apr 2021 10:55:58 -0400 Subject: c++: ICE with invalid use of 'this' with static memfn [PR98800] Here instantiation of the fake 'this' parameter we used when parsing the trailing return type of func() was failing because there is no actual 'this' parameter in the instantiation. For PR97399 I told Patrick to do the 'this' injection even for statics, but now I think I was wrong; the out-of-class definition case I was concerned about does not break with this patch. And we don't set current_class_ptr in the body of a static member function. And the OMP code should continue to parse 'this' and complain about it rather than give a syntax error. gcc/cp/ChangeLog: PR c++/98800 PR c++/97399 * parser.c (cp_parser_direct_declarator): Don't inject_this_parameter if static_p. (cp_parser_omp_var_list_no_open): Parse 'this' even if current_class_ptr isn't set for a better diagnostic. gcc/testsuite/ChangeLog: PR c++/98800 * g++.dg/gomp/this-1.C: Adjust diagnostic. * g++.dg/cpp0x/constexpr-this1.C: New test. --- gcc/cp/parser.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e6e6ed7..b6f94bd 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -22193,7 +22193,7 @@ cp_parser_direct_declarator (cp_parser* parser, tree save_ccp = current_class_ptr; tree save_ccr = current_class_ref; - if (memfn && !friend_p) + if (memfn && !friend_p && !static_p) /* DR 1207: 'this' is in scope after the cv-quals. */ inject_this_parameter (current_class_type, cv_quals); @@ -35283,7 +35283,6 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, cp_parser_parse_tentatively (parser); token = cp_lexer_peek_token (parser->lexer); if (kind != 0 - && current_class_ptr && cp_parser_is_keyword (token, RID_THIS)) { decl = finish_this_expr (); -- cgit v1.1 From 1d54b13841774aa40f5d0a5ab87b19e7e1276d42 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 11 Apr 2021 00:16:24 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5d35496..a6e03cb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2021-04-10 Jason Merrill + + PR c++/98800 + PR c++/97399 + * parser.c (cp_parser_direct_declarator): Don't + inject_this_parameter if static_p. + (cp_parser_omp_var_list_no_open): Parse 'this' even if + current_class_ptr isn't set for a better diagnostic. + +2021-04-10 Jason Merrill + + PR c++/99180 + PR c++/93295 + PR c++/93867 + PR c++/99118 + PR c++/96873 + * pt.c (alias_ctad_tweaks): Handle failure better. + +2021-04-10 Jason Merrill + + PR c++/100006 + * pt.c (find_parameter_packs_r) [TAG_DEFN]: Look into bases. + 2021-04-09 Patrick Palka * cp-tree.h (LAMBDA_EXPR_REGENERATED_FROM) -- cgit v1.1 From 936d500dfc17f58f2507ecd0f7f26e4f197052ee Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 10 Apr 2021 14:00:15 -0400 Subject: c++: ICE with anonymous union [PR97974] Here lookup got confused by finding a conversion operator from lookup_anon_field. Let's avoid this by pruning functions from CLASSTYPE_MEMBER_VEC as well as TYPE_FIELDS. gcc/cp/ChangeLog: PR c++/97974 * decl.c (fixup_anonymous_aggr): Prune all functions from CLASSTYPE_MEMBER_VEC. gcc/testsuite/ChangeLog: PR c++/97974 * g++.dg/lookup/pr84962.C: Adjust diagnostic. * g++.dg/other/anon-union5.C: New test. --- gcc/cp/decl.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 3294b4f..ec05ee1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5005,6 +5005,14 @@ fixup_anonymous_aggr (tree t) else prev_p = &DECL_CHAIN (probe); + /* Splice all functions out of CLASSTYPE_MEMBER_VEC. */ + vec* vec = CLASSTYPE_MEMBER_VEC (t); + unsigned store = 0; + for (tree elt : vec) + if (!is_overloaded_fn (elt)) + (*vec)[store++] = elt; + vec_safe_truncate (vec, store); + /* Anonymous aggregates cannot have fields with ctors, dtors or complex assignment operators (because they cannot have these methods themselves). For anonymous unions this is already checked because they are not allowed -- cgit v1.1 From a0ecde220da1edf7062ec429aa2c7a5b4103e92f Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Mon, 12 Apr 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a6e03cb..fcb7c2a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2021-04-11 Jason Merrill + + PR c++/97974 + * decl.c (fixup_anonymous_aggr): Prune all functions from + CLASSTYPE_MEMBER_VEC. + 2021-04-10 Jason Merrill PR c++/98800 -- cgit v1.1 From 84081e2c6bd43a6790f751755865cf4227adac7c Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 10 Apr 2021 02:10:32 -0400 Subject: c++: premature overload resolution [PR93085] We can't resolve the call to foo<42> before instantiation of G, because the template parameter of #1 has dependent type. But we were missing that in our dependency check, because the tree walk of DECL_TEMPLATE_PARMS doesn't look into the types of template parameters. So look at them directly. gcc/cp/ChangeLog: PR c++/93085 * pt.c (uses_outer_template_parms): Handle non-type and template template parameters specifically. gcc/testsuite/ChangeLog: PR c++/93085 * g++.dg/template/dependent-tmpl1.C: New test. --- gcc/cp/pt.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index abd1ad4..efcbc59 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10846,11 +10846,22 @@ uses_outer_template_parms (tree decl) &depth, NULL, /*include_nondeduced_p=*/true)) return true; if (PRIMARY_TEMPLATE_P (decl) - && for_each_template_parm (INNERMOST_TEMPLATE_PARMS - (DECL_TEMPLATE_PARMS (decl)), - template_parm_outer_level, - &depth, NULL, /*include_nondeduced_p=*/true)) - return true; + || DECL_TEMPLATE_TEMPLATE_PARM_P (decl)) + { + tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (decl)); + for (int i = TREE_VEC_LENGTH (parms) - 1; i >= 0; --i) + { + tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i)); + if (TREE_CODE (parm) == PARM_DECL + && for_each_template_parm (TREE_TYPE (parm), + template_parm_outer_level, + &depth, NULL, /*nondeduced*/true)) + return true; + if (TREE_CODE (parm) == TEMPLATE_DECL + && uses_outer_template_parms (parm)) + return true; + } + } tree ci = get_constraints (decl); if (ci) ci = CI_ASSOCIATED_CONSTRAINTS (ci); -- cgit v1.1 From 287ad814d7703a26d5623a9deafd5932c248d49c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 13 Apr 2021 00:16:21 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fcb7c2a..208c17e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2021-04-12 Jason Merrill + + PR c++/93085 + * pt.c (uses_outer_template_parms): Handle non-type and template + template parameters specifically. + 2021-04-11 Jason Merrill PR c++/97974 -- cgit v1.1 From 59d9aa6d2efe7c52b6a986eb3e1977c1fb3c5753 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 12 Apr 2021 22:54:55 -0400 Subject: c++: constraints are unevaluated operands [PR99961] According to [temp.concept]/6 and [temp.pre]/9, a concept definition and a requires clause are both unevaluated contexts, and hence satisfaction deals only with unevaluated operands, so we should set cp_unevaluated in these three situations. gcc/cp/ChangeLog: PR c++/99961 PR c++/99994 * constraint.cc (satisfy_normalized_constraints): Set cp_unevaluated. * parser.c (cp_parser_concept_definition): Likewise. (cp_parser_requires_clause_opt): Likewise. gcc/testsuite/ChangeLog: PR c++/99961 PR c++/99994 * g++.dg/cpp2a/concepts-uneval1.C: New test. * g++.dg/cpp2a/concepts-uneval2.C: New test. --- gcc/cp/constraint.cc | 3 +++ gcc/cp/parser.c | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 0ddb299..0709695 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3066,6 +3066,9 @@ satisfy_normalized_constraints (tree t, tree args, sat_info info) /* We need to check access during satisfaction. */ deferring_access_check_sentinel acs (dk_no_deferred); + /* Constraints are unevaluated operands. */ + cp_unevaluated u; + return satisfy_constraint_r (t, args, info); } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b6f94bd..8b7801b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -28353,6 +28353,9 @@ cp_parser_label_declaration (cp_parser* parser) static tree cp_parser_concept_definition (cp_parser *parser) { + /* A concept definition is an unevaluated context. */ + cp_unevaluated u; + gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_CONCEPT)); cp_lexer_consume_token (parser->lexer); @@ -28714,6 +28717,9 @@ cp_parser_constraint_expression (cp_parser *parser) static tree cp_parser_requires_clause_opt (cp_parser *parser, bool lambda_p) { + /* A requires clause is an unevaluated context. */ + cp_unevaluated u; + cp_token *tok = cp_lexer_peek_token (parser->lexer); if (tok->keyword != RID_REQUIRES) { -- cgit v1.1 From c755e1b3eadaf1c7e751a2c7ce1d418c6db8463a Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 12 Apr 2021 23:22:03 -0400 Subject: c++: variadic class template placeholder deduction [PR97134] do_class_deduction handles specially the case where we're deducing one placeholder from another equivalent one, but here the initializer passed to do_class_deduction is wrapped in an EXPR_PACK_EXPANSION (we're being called from unify during get_partial_spec_bindings). This patch makes do_class_deduction look through EXPR_PACK_EXPANSIONs so that we detect this case as well. gcc/cp/ChangeLog: PR c++/97134 * pt.c (do_class_deduction): Look through EXPR_PACK_EXPANSION when checking if the initializer is an equivalent class placeholder template parameter. gcc/testsuite/ChangeLog: PR c++/97134 * g++.dg/cpp2a/nontype-class43.C: New test. --- gcc/cp/pt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index efcbc59..6b63edd 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -29286,7 +29286,11 @@ do_class_deduction (tree ptype, tree tmpl, tree init, return ptype; /* Initializing one placeholder from another. */ - if (init && TREE_CODE (init) == TEMPLATE_PARM_INDEX + if (init + && (TREE_CODE (init) == TEMPLATE_PARM_INDEX + || (TREE_CODE (init) == EXPR_PACK_EXPANSION + && (TREE_CODE (PACK_EXPANSION_PATTERN (init)) + == TEMPLATE_PARM_INDEX))) && is_auto (TREE_TYPE (init)) && CLASS_PLACEHOLDER_TEMPLATE (TREE_TYPE (init)) == tmpl) return cp_build_qualified_type (TREE_TYPE (init), cp_type_quals (ptype)); -- cgit v1.1 From 1174314811af52779497462f26d21ea0038d1a85 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Tue, 13 Apr 2021 11:57:55 +0200 Subject: Fix thinko in libcpp preparation patch for modules The problem is that the new IS_MACRO_LOC macro: inline bool IS_MACRO_LOC (location_t loc) { return !IS_ORDINARY_LOC (loc) && !IS_ADHOC_LOC (loc); } is not fully correct since the position of the macro lines is not fixed: /* Returns the lowest location [of a token resulting from macro expansion] encoded in this line table. */ inline location_t LINEMAPS_MACRO_LOWEST_LOCATION (const line_maps *set) { return LINEMAPS_MACRO_USED (set) ? MAP_START_LOCATION (LINEMAPS_LAST_MACRO_MAP (set)) : MAX_LOCATION_T + 1; } In Ada, LINEMAPS_MACRO_USED is false so LINEMAPS_MACRO_LOWEST_LOCATION is MAX_LOCATION_T + 1, but IS_MACRO_LOC nevertheless returns true for anything in the range [LINE_MAP_MAX_LOCATION; MAX_LOCATION_T], thus yielding an ICE in linemap_macro_map_lookup for very large files. libcpp/ * include/line-map.h (IS_MACRO_LOC): Delete. * line-map.c (linemap_location_from_macro_expansion_p): Test LINEMAPS_MACRO_LOWEST_LOCATION of the linemap. gcc/cp/ * module.cc (ordinary_loc_of): Test LINEMAPS_MACRO_LOWEST_LOCATION of the linemap. (module_state::write_location): Likewise. --- gcc/cp/module.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index c80c7bc..ab8b1f1 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -13709,7 +13709,7 @@ ordinary_loc_of (line_maps *lmaps, location_t from) { if (IS_ADHOC_LOC (from)) from = get_location_from_adhoc_loc (lmaps, from); - if (IS_MACRO_LOC (from)) + if (from >= LINEMAPS_MACRO_LOWEST_LOCATION (lmaps)) { /* Find the ordinary location nearest FROM. */ const line_map *map = linemap_lookup (lmaps, from); @@ -15554,7 +15554,7 @@ module_state::write_location (bytes_out &sec, location_t loc) write_location (sec, range.m_start); write_location (sec, range.m_finish); } - else if (IS_MACRO_LOC (loc)) + else if (loc >= LINEMAPS_MACRO_LOWEST_LOCATION (line_table)) { if (const loc_spans::span *span = spans.macro (loc)) { -- cgit v1.1 From 0851ac6df0596df1e3b640e58094cf94ebb790b8 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 12 Apr 2021 17:43:51 -0400 Subject: c++: constexpr, inheritance, and local class [PR91933] Here we complained about referring to nm3 from the local class member function because referring to the base class subobject involved taking the variable's address. Let's shortcut this case to avoid that. gcc/cp/ChangeLog: PR c++/91933 * class.c (build_base_path): Shortcut simple non-pointer case. gcc/testsuite/ChangeLog: PR c++/91933 * g++.dg/cpp0x/constexpr-base7.C: New test. --- gcc/cp/class.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 4bffec4..90b3438 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -330,6 +330,15 @@ build_base_path (enum tree_code code, return error_mark_node; } + bool uneval = (cp_unevaluated_operand != 0 + || processing_template_decl + || in_template_function ()); + + /* For a non-pointer simple base reference, express it as a COMPONENT_REF + without taking its address (and so causing lambda capture, 91933). */ + if (code == PLUS_EXPR && !v_binfo && !want_pointer && !has_empty && !uneval) + return build_simple_base_path (expr, binfo); + if (!want_pointer) { rvalue = !lvalue_p (expr); @@ -357,9 +366,7 @@ build_base_path (enum tree_code code, template (even in instantiate_non_dependent_expr), we don't have vtables set up properly yet, and the value doesn't matter there either; we're just interested in the result of overload resolution. */ - if (cp_unevaluated_operand != 0 - || processing_template_decl - || in_template_function ()) + if (uneval) { expr = build_nop (ptr_target_type, expr); goto indout; -- cgit v1.1 From 8913b2c2bcded39427ff27e6dfc276ae8555f6b8 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 13 Apr 2021 12:35:33 -0400 Subject: c++: Reject alias CTAD in C++17 [PR99008] Here, in C++17 mode, we only pedwarn about the use of alias CTAD and then later ICE from alias_ctad_tweaks when attempting to constrain the guides. Since the construction of the guides of an alias template effectively relies on concepts, we shouldn't be permissive about alias CTAD in C++17 mode, so this patch turns the pertinent pedwarn in do_class_deduction into an error. In order to get a consistent diagnostic for B() vs the other forms in the added testcase, I had to remove the special handling of CTAD with empty initializer in build_functional_cast_1 so that we always pass 'complain' to do_auto_deduction. gcc/cp/ChangeLog: PR c++/99008 * pt.c (do_class_deduction): Reject alias CTAD in C++17 mode rather than issuing a pedwarn. * typeck2.c (build_functional_cast_1): Handle CTAD uniformly for consistent diagnostics. gcc/testsuite/ChangeLog: PR c++/99008 * g++.dg/parse/template2.C: Adjust expected diagnostic. * g++.dg/template/error8.C: Likewise. * g++.dg/cpp1z/class-deduction84.C: New test. --- gcc/cp/pt.c | 8 ++++---- gcc/cp/typeck2.c | 17 +++-------------- 2 files changed, 7 insertions(+), 18 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 6b63edd..106dfe5 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -29305,10 +29305,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init, } else if (cxx_dialect < cxx20 && DECL_ALIAS_TEMPLATE_P (tmpl)) { - /* This doesn't affect conforming C++17 code, so just pedwarn. */ - if (complain & tf_warning_or_error) - pedwarn (input_location, 0, "alias template deduction only available " - "with %<-std=c++20%> or %<-std=gnu++20%>"); + if (complain & tf_error) + error ("alias template deduction only available " + "with %<-std=c++20%> or %<-std=gnu++20%>"); + return error_mark_node; } tree type = TREE_TYPE (tmpl); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index a58d397..4e9632f 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -2197,24 +2197,13 @@ build_functional_cast_1 (location_t loc, tree exp, tree parms, error_at (loc, "invalid use of %qT", anode); return error_mark_node; } - else if (!parms) + else { - /* Even if there are no parameters, we might be able to deduce from - default template arguments. Pass TF_NONE so that we don't - generate redundant diagnostics. */ - type = do_auto_deduction (type, parms, anode, tf_none, + type = do_auto_deduction (type, parms, anode, complain, adc_variable_type); if (type == error_mark_node) - { - if (complain & tf_error) - error_at (loc, "cannot deduce template arguments " - "for %qT from %<()%>", anode); - return error_mark_node; - } + return error_mark_node; } - else - type = do_auto_deduction (type, parms, anode, complain, - adc_variable_type); } if (processing_template_decl) -- cgit v1.1 From 6173f713a35d5450f0e2acfdaec695b42632aeed Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 13 Apr 2021 12:33:39 -0400 Subject: c++: generic lambda in template fn with DMI [PR100054] get_nsdmi instantiates default member initializers on demand. It tries to push into the context of the class before doing so, so access checking works properly, but since my patch for 90479 not for local classes. We should only be doing this when any template parameters have arguments. But in this case, we get here while regenerating a generic lambda, so processing_template_decl is true, even though the class and its DMI are non-dependent at this point. And so we crashed. So let's do more of the pushing into the context of the class even for local classes. gcc/cp/ChangeLog: PR c++/100054 PR c++/90479 * init.c (get_nsdmi): Do more context adjustment for local classes. gcc/testsuite/ChangeLog: PR c++/100054 * g++.dg/cpp1y/lambda-generic-local-class1.C: New test. --- gcc/cp/init.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 91b45a1..a85f4d5 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -586,17 +586,21 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain) bool pushed = false; tree ctx = DECL_CONTEXT (member); - if (!currently_open_class (ctx) - && !LOCAL_CLASS_P (ctx)) + + processing_template_decl_sentinel ptds (/*reset*/false); + if (!currently_open_class (ctx)) { - push_to_top_level (); + if (!LOCAL_CLASS_P (ctx)) + push_to_top_level (); + else + /* push_to_top_level would lose the necessary function context, + just reset processing_template_decl. */ + processing_template_decl = 0; push_nested_class (ctx); push_deferring_access_checks (dk_no_deferred); pushed = true; } - gcc_checking_assert (!processing_template_decl); - inject_this_parameter (ctx, TYPE_UNQUALIFIED); start_lambda_scope (member); @@ -619,7 +623,8 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain) { pop_deferring_access_checks (); pop_nested_class (); - pop_from_top_level (); + if (!LOCAL_CLASS_P (ctx)) + pop_from_top_level (); } input_location = sloc; -- cgit v1.1 From 34ec63f1b5c2a4d39aa3b13ade96bcd44e294066 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 13 Apr 2021 14:49:29 -0400 Subject: c++: alias template equivalence and cv-quals [PR100032] We also need to check that the cv-qualifiers are the same. gcc/cp/ChangeLog: PR c++/100032 * pt.c (get_underlying_template): Compare TYPE_QUALS. gcc/testsuite/ChangeLog: PR c++/100032 * g++.dg/cpp0x/alias-decl-equiv1.C: New test. --- gcc/cp/pt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 106dfe5..59df794 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6584,6 +6584,10 @@ get_underlying_template (tree tmpl) != num_innermost_template_parms (underlying))) break; + /* Does the alias add cv-quals? */ + if (TYPE_QUALS (TREE_TYPE (underlying)) != TYPE_QUALS (TREE_TYPE (tmpl))) + break; + tree alias_args = INNERMOST_TEMPLATE_ARGS (generic_targs_for (tmpl)); if (!comp_template_args (TI_ARGS (tinfo), alias_args)) break; -- cgit v1.1 From 6d0d35d518a12ee43c1fbd77df73a66d02305a69 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 14 Apr 2021 00:16:24 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 208c17e..9145630 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,49 @@ +2021-04-13 Jason Merrill + + PR c++/100032 + * pt.c (get_underlying_template): Compare TYPE_QUALS. + +2021-04-13 Jason Merrill + + PR c++/100054 + PR c++/90479 + * init.c (get_nsdmi): Do more context adjustment for local classes. + +2021-04-13 Patrick Palka + + PR c++/99008 + * pt.c (do_class_deduction): Reject alias CTAD in C++17 mode + rather than issuing a pedwarn. + * typeck2.c (build_functional_cast_1): Handle CTAD uniformly + for consistent diagnostics. + +2021-04-13 Jason Merrill + + PR c++/91933 + * class.c (build_base_path): Shortcut simple non-pointer case. + +2021-04-13 Eric Botcazou + + * module.cc (ordinary_loc_of): Test LINEMAPS_MACRO_LOWEST_LOCATION + of the linemap. + (module_state::write_location): Likewise. + +2021-04-13 Patrick Palka + + PR c++/97134 + * pt.c (do_class_deduction): Look through EXPR_PACK_EXPANSION + when checking if the initializer is an equivalent class + placeholder template parameter. + +2021-04-13 Patrick Palka + + PR c++/99961 + PR c++/99994 + * constraint.cc (satisfy_normalized_constraints): Set + cp_unevaluated. + * parser.c (cp_parser_concept_definition): Likewise. + (cp_parser_requires_clause_opt): Likewise. + 2021-04-12 Jason Merrill PR c++/93085 -- 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/parser.c | 5 +++-- gcc/cp/semantics.c | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 8b7801b..aec3aa3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -12126,11 +12126,12 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr, if (function_body) maybe_splice_retval_cleanup (compound_stmt); - /* Finish the compound-statement. */ - finish_compound_stmt (compound_stmt); /* Consume the `}'. */ braces.require_close (parser); + /* Finish the compound-statement. */ + finish_compound_stmt (compound_stmt); + return compound_stmt; } 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 0589be0c59767cf4cbb0ef0e7d918cf6aa3d606c Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 13 Apr 2021 20:32:13 -0400 Subject: c++: DWARF ICE with defaulted specialization [PR90674] Here when we merged the specialization with the implicit instantiation declaration, we wrongly kept the value of DECL_INITIALIZED_IN_CLASS_P from the latter. gcc/cp/ChangeLog: PR c++/90674 * decl.c (duplicate_decls): Don't propagate DECL_INITIALIZED_IN_CLASS_P to a specialization. gcc/testsuite/ChangeLog: PR c++/90674 * g++.dg/debug/defaulted1.C: New test. --- gcc/cp/decl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index ec05ee1..1cb4731 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2556,8 +2556,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (!DECL_USE_TEMPLATE (newdecl)) DECL_USE_TEMPLATE (newdecl) = DECL_USE_TEMPLATE (olddecl); - DECL_INITIALIZED_IN_CLASS_P (newdecl) - |= DECL_INITIALIZED_IN_CLASS_P (olddecl); + if (!DECL_TEMPLATE_SPECIALIZATION (newdecl)) + DECL_INITIALIZED_IN_CLASS_P (newdecl) + |= DECL_INITIALIZED_IN_CLASS_P (olddecl); } /* Don't really know how much of the language-specific -- cgit v1.1 From e1666ebd9ad31dbd8b9b933c883bdd882cfd1522 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 13 Apr 2021 22:28:32 -0400 Subject: c++: lambda in non-type template parm type [PR99478] In this testcase, the non-type template parameter has the type of a lambda-expression. This makes no sense because a lambda in template context is specified to be distinct between different specializations of the template, even if the lambda is non-dependent, but here which specialization we are dealing with depends on which lambda we have, and vice versa. gcc/cp/ChangeLog: PR c++/99478 * parser.c (cp_parser_lambda_expression): Reject lambda in template parameter type. gcc/testsuite/ChangeLog: PR c++/99478 * g++.dg/cpp2a/lambda-uneval14.C: New test. --- gcc/cp/parser.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index aec3aa3..3a10720 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -10796,7 +10796,21 @@ cp_parser_lambda_expression (cp_parser* parser) LAMBDA_EXPR_LOCATION (lambda_expr) = token->location; if (cxx_dialect >= cxx20) - /* C++20 allows lambdas in unevaluated context. */; + { + /* C++20 allows lambdas in unevaluated context, but one in the type of a + non-type parameter is nonsensical. + + Distinguish a lambda in the parameter type from a lambda in the + default argument by looking at local_variables_forbidden_p, which is + only set in default arguments. */ + if (processing_template_parmlist && !parser->local_variables_forbidden_p) + { + error_at (token->location, + "lambda-expression in template parameter type"); + token->error_reported = true; + ok = false; + } + } else if (cp_unevaluated_operand) { if (!token->error_reported) -- cgit v1.1 From 2ccc05a5141506fde0e20dec702c717fd67bf6ee Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 14 Apr 2021 08:54:30 -0400 Subject: c++: Fix deduction with reference NTTP [PR83476] In the testcase ref11.C below, during deduction for the call f(a), uses_deducible_template_parms returns false for the dependent specialization A because the generic template argument V here is wrapped in an implicit INDIRECT_REF (formed from template_parm_to_arg). Since uses_deducible_template_parms returns false, unify_one_argument exits early without ever attempting to deduce 'n' for 'V'. This patch fixes this by making deducible_expression look through such implicit INDIRECT_REFs. gcc/cp/ChangeLog: PR c++/83476 PR c++/99885 * pt.c (deducible_expression): Look through implicit INDIRECT_REFs as well. gcc/testsuite/ChangeLog: PR c++/83476 PR c++/99885 * g++.dg/cpp1z/class-deduction85.C: New test. * g++.dg/template/ref11.C: New test. --- gcc/cp/pt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 59df794..f488a5a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -21902,8 +21902,10 @@ static bool uses_deducible_template_parms (tree type); static bool deducible_expression (tree expr) { - /* Strip implicit conversions. */ - while (CONVERT_EXPR_P (expr) || TREE_CODE (expr) == VIEW_CONVERT_EXPR) + /* Strip implicit conversions and implicit INDIRECT_REFs. */ + while (CONVERT_EXPR_P (expr) + || TREE_CODE (expr) == VIEW_CONVERT_EXPR + || REFERENCE_REF_P (expr)) expr = TREE_OPERAND (expr, 0); return (TREE_CODE (expr) == TEMPLATE_PARM_INDEX); } -- 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') 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 00a2774923c1dc5666cd26bb9b8c37b1b7dd689d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 14 Apr 2021 14:14:31 -0400 Subject: c++: premature overload resolution redux [PR100078] My patch for PR93085 didn't consider that a default template argument can also make a template dependent. gcc/cp/ChangeLog: PR c++/100078 PR c++/93085 * pt.c (uses_outer_template_parms): Also look at default template argument. gcc/testsuite/ChangeLog: PR c++/100078 * g++.dg/template/dependent-tmpl2.C: New test. --- gcc/cp/pt.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f488a5a..0f119a5 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10856,6 +10856,7 @@ uses_outer_template_parms (tree decl) for (int i = TREE_VEC_LENGTH (parms) - 1; i >= 0; --i) { tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i)); + tree defarg = TREE_PURPOSE (TREE_VEC_ELT (parms, i)); if (TREE_CODE (parm) == PARM_DECL && for_each_template_parm (TREE_TYPE (parm), template_parm_outer_level, @@ -10864,6 +10865,10 @@ uses_outer_template_parms (tree decl) if (TREE_CODE (parm) == TEMPLATE_DECL && uses_outer_template_parms (parm)) return true; + if (defarg + && for_each_template_parm (defarg, template_parm_outer_level, + &depth, NULL, /*nondeduced*/true)) + return true; } } tree ci = get_constraints (decl); -- cgit v1.1 From df3b1289521e6f24d5151fc5f7b135b8bf3009bc Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 15 Apr 2021 00:16:47 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9145630..e508222 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,45 @@ +2021-04-14 Jason Merrill + + PR c++/100078 + PR c++/93085 + * pt.c (uses_outer_template_parms): Also look at default + template argument. + +2021-04-14 Jason Merrill + + PR c++/93314 + * semantics.c (finish_id_expression_1): Clear cp_unevaluated_operand + for a non-static data member in a constant-expression. + +2021-04-14 Patrick Palka + + PR c++/83476 + PR c++/99885 + * pt.c (deducible_expression): Look through implicit + INDIRECT_REFs as well. + +2021-04-14 Jason Merrill + + PR c++/99478 + * parser.c (cp_parser_lambda_expression): Reject lambda + in template parameter type. + +2021-04-14 Jason Merrill + + PR c++/90674 + * decl.c (duplicate_decls): Don't propagate + DECL_INITIALIZED_IN_CLASS_P to a specialization. + +2021-04-14 Jason Merrill + + 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. + 2021-04-13 Jason Merrill PR c++/100032 -- cgit v1.1 From 1696fc1ea01d5c9dce96b5d3122921aab9308f59 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 15 Apr 2021 11:37:39 +0100 Subject: c++: Tweak merging of vector attributes that affect type identity [PR98852] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit types are distinct from GNU vector types in at least their mangling. However, there used to be nothing explicit in the VECTOR_TYPE itself to indicate the difference: we simply treated them as distinct TYPE_MAIN_VARIANTs. This caused problems like the ones reported in PR95726. The fix for that PR was to add type attributes to the types, in order to maintain the distinction between them and GNU vectors. However, this in turn caused PR98852, where cp_common_type would merge the type attributes from the two source types and attach the result to the common type. For example: unsigned vector with no attribute + signed vector with attribute X would get converted to: unsigned vector with attribute X That isn't what we want in this case, since X describes the mangling of the original type. But even if we dropped the mangling from X and worked it out from context, we would still have a situation in which the common type was provably distinct from both of the source types: it would take its -ness from one side and its signedness from the other. I guess there are other cases where the common type doesn't match either side, but I'm not sure it's the obvious behaviour here. It's also different from GCC 10.1 and earlier, where the unsigned vector “won” in its original form. This patch instead merges only the attributes that don't affect type identity. For now I've restricted it to vector types, since we're so close to GCC 11, but it might make sense to use this elsewhere. I've tried to audit the C and target-specific attributes to look for other types that might be affected by this, but I couldn't see any. The closest was s390_vector_bool, but the handler for that attribute changes the type node and drops the attribute itself (*no_add_attrs = true). gcc/ PR c++/98852 * attribs.h (restrict_type_identity_attributes_to): Declare. * attribs.c (restrict_type_identity_attributes_to): New function. gcc/cp/ PR c++/98852 * typeck.c (merge_type_attributes_from): New function. (cp_common_type): Use it for vector types. --- gcc/cp/typeck.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 11dee7d..50d0f1e 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -261,6 +261,17 @@ original_type (tree t) return cp_build_qualified_type (t, quals); } +/* Merge the attributes of type OTHER_TYPE into the attributes of type TYPE + and return a variant of TYPE with the merged attributes. */ + +static tree +merge_type_attributes_from (tree type, tree other_type) +{ + tree attrs = targetm.merge_type_attributes (type, other_type); + attrs = restrict_type_identity_attributes_to (attrs, TYPE_ATTRIBUTES (type)); + return cp_build_type_attribute_variant (type, attrs); +} + /* Return the common type for two arithmetic types T1 and T2 under the usual arithmetic conversions. The default conversions have already been applied, and enumerated types converted to their compatible @@ -320,9 +331,9 @@ cp_common_type (tree t1, tree t2) /* When we get here we should have two vectors of the same size. Just prefer the unsigned one if present. */ if (TYPE_UNSIGNED (t1)) - return build_type_attribute_variant (t1, attributes); + return merge_type_attributes_from (t1, t2); else - return build_type_attribute_variant (t2, attributes); + return merge_type_attributes_from (t2, t1); } /* If only one is real, use it as the result. */ -- cgit v1.1 From 432f60c90dfb27f77e6f437bf1148f37bf73d70e Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 15 Apr 2021 12:16:48 -0400 Subject: c++: lambda in default type template-argument [PR100091] My patch for 99478 relied on local_variables_forbidden_p for distinguishing between a template parameter and its default argument, but that flag wasn't set for a default type template-argument. gcc/cp/ChangeLog: PR c++/100091 PR c++/99478 * parser.c (cp_parser_default_type_template_argument): Set parser->local_variables_forbidden_p. gcc/testsuite/ChangeLog: PR c++/100091 * g++.dg/cpp2a/lambda-uneval15.C: New test. --- gcc/cp/parser.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 3a10720..940751b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16923,6 +16923,10 @@ cp_parser_default_type_template_argument (cp_parser *parser) cp_token *token = cp_lexer_peek_token (parser->lexer); + /* Tell cp_parser_lambda_expression this is a default argument. */ + auto lvf = make_temp_override (parser->local_variables_forbidden_p); + parser->local_variables_forbidden_p = LOCAL_VARS_AND_THIS_FORBIDDEN; + /* Parse the default-argument. */ push_deferring_access_checks (dk_no_deferred); tree default_argument = cp_parser_type_id (parser, -- cgit v1.1 From 2efbbba16a0630fac8cadcd6d9e0ffaabfadb79f Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 15 Apr 2021 13:38:54 -0400 Subject: c++: noexcept error recursion [PR100101] Here instantiating the noexcept-specifier for bar() means instantiating A::value, which complains about the conversion from 0 to int* in the default argument of foo. Since my patch for PR99583, printing the error context involves looking at C::type, which again wants to instantiate A::value, which breaks. For now at least, let's break this recursion by avoiding looking into the noexcept-specifier in find_typenames, and limit that to just the uses_parameter_packs case that PR99583 cares about. gcc/cp/ChangeLog: PR c++/100101 PR c++/99583 * pt.c (find_parameter_packs_r) [FUNCTION_TYPE]: Walk into TYPE_RAISES_EXCEPTIONS here. * tree.c (cp_walk_subtrees): Not here. gcc/testsuite/ChangeLog: PR c++/100101 * g++.dg/cpp0x/noexcept67.C: New test. --- gcc/cp/pt.c | 11 +++++++++++ gcc/cp/tree.c | 5 ----- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0f119a5..2190f83 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -3890,6 +3890,10 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) (struct find_parameter_pack_data*)data; bool parameter_pack_p = false; +#define WALK_SUBTREE(NODE) \ + cp_walk_tree (&(NODE), &find_parameter_packs_r, \ + ppd, ppd->visited) \ + /* Don't look through typedefs; we are interested in whether a parameter pack is actually written in the expression/type we're looking at, not the target type. */ @@ -4070,10 +4074,17 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) ppd, ppd->visited); return NULL_TREE; + case FUNCTION_TYPE: + case METHOD_TYPE: + WALK_SUBTREE (TYPE_RAISES_EXCEPTIONS (t)); + break; + default: return NULL_TREE; } +#undef WALK_SUBTREE + return NULL_TREE; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 13cc61c..dca947b 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -5415,11 +5415,6 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, } break; - case FUNCTION_TYPE: - case METHOD_TYPE: - WALK_SUBTREE (TYPE_RAISES_EXCEPTIONS (*tp)); - break; - default: return NULL_TREE; } -- cgit v1.1 From 3682052e4ccf0a29d1f61df1c8e31f8190eafafe Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 15 Apr 2021 15:13:18 -0400 Subject: c++: constexpr and volatile member function [PR80456] When calling a static member function we still need to evaluate an explicit object argument. But we don't want to force a load of the entire object if the argument is volatile, so we take its address. If as a result it no longer has any side-effects, we don't need to evaluate it after all. gcc/cp/ChangeLog: PR c++/80456 * call.c (build_new_method_call_1): Check again for side-effects with a volatile object. gcc/testsuite/ChangeLog: PR c++/80456 * g++.dg/cpp0x/constexpr-volatile3.C: New test. --- gcc/cp/call.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index c9a8c0d..678e120a 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -10793,7 +10793,8 @@ build_new_method_call_1 (tree instance, tree fns, vec **args, tree a = instance; if (TREE_THIS_VOLATILE (a)) a = build_this (a); - call = build2 (COMPOUND_EXPR, TREE_TYPE (call), a, call); + if (TREE_SIDE_EFFECTS (a)) + call = build2 (COMPOUND_EXPR, TREE_TYPE (call), a, call); } else if (call != error_mark_node && DECL_DESTRUCTOR_P (cand->fn) -- cgit v1.1 From ee351f7fdbd82f8947fe9a0e74cea65d216a8549 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 16 Apr 2021 00:16:23 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e508222..b5c21bf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,30 @@ +2021-04-15 Jason Merrill + + PR c++/80456 + * call.c (build_new_method_call_1): Check again for side-effects + with a volatile object. + +2021-04-15 Jason Merrill + + PR c++/100101 + PR c++/99583 + * pt.c (find_parameter_packs_r) [FUNCTION_TYPE]: Walk into + TYPE_RAISES_EXCEPTIONS here. + * tree.c (cp_walk_subtrees): Not here. + +2021-04-15 Jason Merrill + + PR c++/100091 + PR c++/99478 + * parser.c (cp_parser_default_type_template_argument): Set + parser->local_variables_forbidden_p. + +2021-04-15 Richard Sandiford + + PR c++/98852 + * typeck.c (merge_type_attributes_from): New function. + (cp_common_type): Use it for vector types. + 2021-04-14 Jason Merrill PR c++/100078 -- cgit v1.1 From 89c863488bc8c7315596bcb753173aa2fd8be727 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 14 Apr 2021 17:27:19 -0400 Subject: c++: C++20 class NTTP trailing zero-init [PR100079] The new testcase was breaking because constexpr evaluation was simplifying Bar{Baz<42>{}} to Bar{empty}, but then we weren't treating them as equivalent. Poking at this revealed that the code for eliding trailing zero-initialization in class non-type template argument mangling was pretty broken, including the test, mangle71. I dealt with the FIXME to support RANGE_EXPR, and fixed the confusion between a list-initialized temporary mangled as written (i.e. in the signature of a function template) and a template parameter object mangled as the value representation of the object. I'm distinguishing between these using COMPOUND_LITERAL_P. A later patch will adjust the use of COMPOUND_LITERAL_P to be more useful for this distinction, but it works now for distinguishing these cases in mangling. gcc/cp/ChangeLog: PR c++/100079 * cp-tree.h (first_field): Declare. * mangle.c (range_expr_nelts): New. (write_expression): Improve class NTTP mangling. * pt.c (get_template_parm_object): Clear TREE_HAS_CONSTRUCTOR. * tree.c (zero_init_expr_p): Improve class NTTP handling. * decl.c: Adjust comment. gcc/testsuite/ChangeLog: PR c++/100079 * g++.dg/abi/mangle71.C: Fix expected mangling. * g++.dg/abi/mangle77.C: New test. * g++.dg/cpp2a/nontype-class-union1.C: Likewise. * g++.dg/cpp2a/nontype-class-equiv1.C: Removed. * g++.dg/cpp2a/nontype-class44.C: New test. --- gcc/cp/cp-tree.h | 1 + gcc/cp/decl.c | 2 +- gcc/cp/mangle.c | 40 ++++++++++++++++++++++++++++++---------- gcc/cp/pt.c | 3 +++ gcc/cp/tree.c | 28 +++++++++++++++++++--------- 5 files changed, 54 insertions(+), 20 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e42b82a..23a77a2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6695,6 +6695,7 @@ extern void initialize_artificial_var (tree, vec *); extern tree check_var_type (tree, tree, location_t); extern tree reshape_init (tree, tree, tsubst_flags_t); extern tree next_initializable_field (tree); +extern tree first_field (const_tree); extern tree fndecl_declared_return_type (tree); extern bool undeduced_auto_decl (tree); extern bool require_deduced_type (tree, tsubst_flags_t = tf_warning_or_error); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 1cb4731..d40b7a7 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6152,7 +6152,7 @@ struct reshape_iter static tree reshape_init_r (tree, reshape_iter *, tree, tsubst_flags_t); -/* FIELD is a FIELD_DECL or NULL. In the former case, the value +/* FIELD is an element of TYPE_FIELDS or NULL. In the former case, the value returned is the next FIELD_DECL (possibly FIELD itself) that can be initialized. If there are no more such fields, the return value will be NULL. */ diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 4399165..49f1266 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2940,6 +2940,16 @@ write_base_ref (tree expr, tree base = NULL_TREE) return true; } +/* The number of elements spanned by a RANGE_EXPR. */ + +unsigned HOST_WIDE_INT +range_expr_nelts (tree expr) +{ + tree lo = TREE_OPERAND (expr, 0); + tree hi = TREE_OPERAND (expr, 1); + return tree_to_uhwi (hi) - tree_to_uhwi (lo) + 1; +} + /* ::= ::= ::= @@ -3284,8 +3294,14 @@ write_expression (tree expr) write_type (etype); } - bool nontriv = !trivial_type_p (etype); - if (nontriv || !zero_init_expr_p (expr)) + /* If this is an undigested initializer, mangle it as written. + COMPOUND_LITERAL_P doesn't actually distinguish between digested and + undigested braced casts, but it should work to use it to distinguish + between braced casts in a template signature (undigested) and template + parm object values (digested), and all CONSTRUCTORS that get here + should be one of those two cases. */ + bool undigested = braced_init || COMPOUND_LITERAL_P (expr); + if (undigested || !zero_init_expr_p (expr)) { /* Convert braced initializer lists to STRING_CSTs so that A<"Foo"> mangles the same as A<{'F', 'o', 'o', 0}> while @@ -3296,28 +3312,32 @@ write_expression (tree expr) if (TREE_CODE (expr) == CONSTRUCTOR) { vec *elts = CONSTRUCTOR_ELTS (expr); - unsigned last_nonzero = UINT_MAX, i; + unsigned last_nonzero = UINT_MAX; constructor_elt *ce; - tree val; - if (!nontriv) - FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val) - if (!zero_init_expr_p (val)) + if (!undigested) + for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i) + if ((TREE_CODE (etype) == UNION_TYPE + && ce->index != first_field (etype)) + || !zero_init_expr_p (ce->value)) last_nonzero = i; - if (nontriv || last_nonzero != UINT_MAX) + if (undigested || last_nonzero != UINT_MAX) for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i) { if (i > last_nonzero) break; - /* FIXME handle RANGE_EXPR */ if (TREE_CODE (etype) == UNION_TYPE) { /* Express the active member as a designator. */ write_string ("di"); write_unqualified_name (ce->index); } - write_expression (ce->value); + unsigned reps = 1; + if (ce->index && TREE_CODE (ce->index) == RANGE_EXPR) + reps = range_expr_nelts (ce->index); + for (unsigned j = 0; j < reps; ++j) + write_expression (ce->value); } } else diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2190f83..a0ca65c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -7150,6 +7150,9 @@ get_template_parm_object (tree expr, tsubst_flags_t complain) if (invalid_tparm_referent_p (TREE_TYPE (expr), expr, complain)) return error_mark_node; + /* This is no longer a compound literal. */ + TREE_HAS_CONSTRUCTOR (expr) = 0; + tree name = mangle_template_parm_object (expr); tree decl = get_global_binding (name); if (decl) diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index dca947b..a8bfd5f 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -4680,20 +4680,30 @@ zero_init_expr_p (tree t) tree type = TREE_TYPE (t); if (!type || uses_template_parms (type)) return false; - if (zero_init_p (type)) - return initializer_zerop (t); if (TYPE_PTRMEM_P (type)) return null_member_pointer_value_p (t); - if (TREE_CODE (t) == CONSTRUCTOR - && CP_AGGREGATE_TYPE_P (type)) + if (TREE_CODE (t) == CONSTRUCTOR) { - tree elt_init; - unsigned HOST_WIDE_INT i; - FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), i, elt_init) - if (!zero_init_expr_p (elt_init)) - return false; + if (CONSTRUCTOR_IS_DEPENDENT (t) + || BRACE_ENCLOSED_INITIALIZER_P (t)) + /* Undigested, conversions might change the zeroness. + + Other COMPOUND_LITERAL_P in template context are also undigested, + but there isn't currently a way to distinguish between them and + COMPOUND_LITERAL_P from non-template context that are digested. */ + return false; + for (constructor_elt &elt : CONSTRUCTOR_ELTS (t)) + { + if (TREE_CODE (type) == UNION_TYPE + && elt.index != first_field (type)) + return false; + if (!zero_init_expr_p (elt.value)) + return false; + } return true; } + if (zero_init_p (type)) + return initializer_zerop (t); return false; } -- cgit v1.1 From 20eb7a1891cfd7fa85295a236cebe0322d041edd Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 16 Apr 2021 09:32:44 +0200 Subject: c++: Fix up handling of structured bindings in extract_locals_r [PR99833] The following testcase ICEs in tsubst_decomp_names because the assumptions that the structured binding artificial var is followed in DECL_CHAIN by the corresponding structured binding vars is violated. I've tracked it to extract_locals* which is done for the constexpr IF_STMT. extract_locals_r when it sees a DECL_EXPR adds that decl into a hash set so that such decls aren't returned from extract_locals*, but in the case of a structured binding that just means the artificial var and not the vars corresponding to structured binding identifiers. The following patch fixes it by pushing not just the artificial var for structured bindings but also the other vars. 2021-04-16 Jakub Jelinek PR c++/99833 * pt.c (extract_locals_r): When handling DECL_EXPR of a structured binding, add to data.internal also all corresponding structured binding decls. * g++.dg/cpp1z/pr99833.C: New test. * g++.dg/cpp2a/pr99833.C: New test. --- gcc/cp/pt.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a0ca65c..19fdafa 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12830,7 +12830,27 @@ extract_locals_r (tree *tp, int */*walk_subtrees*/, void *data_) tp = &TYPE_NAME (*tp); if (TREE_CODE (*tp) == DECL_EXPR) - data.internal.add (DECL_EXPR_DECL (*tp)); + { + tree decl = DECL_EXPR_DECL (*tp); + data.internal.add (decl); + if (VAR_P (decl) + && DECL_DECOMPOSITION_P (decl) + && TREE_TYPE (decl) != error_mark_node) + { + gcc_assert (DECL_NAME (decl) == NULL_TREE); + for (tree decl2 = DECL_CHAIN (decl); + decl2 + && VAR_P (decl2) + && DECL_DECOMPOSITION_P (decl2) + && DECL_NAME (decl2) + && TREE_TYPE (decl2) != error_mark_node; + decl2 = DECL_CHAIN (decl2)) + { + gcc_assert (DECL_DECOMP_BASE (decl2) == decl); + data.internal.add (decl2); + } + } + } else if (TREE_CODE (*tp) == LAMBDA_EXPR) { /* Since we defer implicit capture, look in the parms and body. */ -- cgit v1.1 From 784de5292c34e287c848b382b431599b818ea76e Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 16 Apr 2021 09:34:26 +0200 Subject: c++: Fix up C++23 [] <...> requires primary -> type {} parsing [PR99850] The requires clause parsing has code to suggest users wrapping non-primary expressions in (), so if it e.g. parses a primary expression and sees it is followed by ++, --, ., ( or -> among other things it will try to reparse it as assignment expression or what and if that works suggests wrapping it inside of parens. When it is requires-clause that is after etc. it already has an exception from that as ( can occur in valid C++20 expression there - starting the parameters of the lambda. In C++23 another case can occur, as the parameters with the ()s can be omitted, requires C can be followed immediately by -> which starts a trailing return type. Even in that case, we don't want to parse that as C->... 2021-04-16 Jakub Jelinek PR c++/99850 * parser.c (cp_parser_constraint_requires_parens) : If lambda_p, return pce_ok instead of pce_maybe_postfix. * g++.dg/cpp23/lambda-specifiers2.C: New test. --- gcc/cp/parser.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 940751b..dfc9b82 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -28530,7 +28530,20 @@ cp_parser_constraint_requires_parens (cp_parser *parser, bool lambda_p) case CPP_PLUS_PLUS: case CPP_MINUS_MINUS: case CPP_DOT: + /* Unenclosed postfix operator. */ + return pce_maybe_postfix; + case CPP_DEREF: + /* A primary constraint that precedes the lambda-declarator of a + lambda expression is followed by trailing return type. + + [] requires C -> void {} + + Don't try to re-parse this as a postfix expression in + C++23 and later. In C++20 ( needs to come in between but we + allow it to be omitted with pedwarn. */ + if (lambda_p) + return pce_ok; /* Unenclosed postfix operator. */ return pce_maybe_postfix; } -- cgit v1.1 From baf05d54dc919c968d12de9d049e36e5bac10dec Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 16 Apr 2021 09:24:46 -0400 Subject: c++: partially initialized constexpr array [PR99700] Here, reduced_constant_expression_p is incorrectly returning true for a partially initialized array CONSTRUCTOR (in C++20 mode) because when the CONSTRUCTOR_NO_CLEARING flag is set, the predicate doesn't check that the CONSTRUCTOR spans the entire array like it does for class CONSTRUCTORS. This patch adds a dedicated loop for the array case that simultaneously verifies the CONSTRUCTOR spans the entire array and is made up of valid constant expressions. gcc/cp/ChangeLog: PR c++/99700 * constexpr.c (reduced_constant_expression_p): For array CONSTRUCTORs, use a dedicated loop that additionally verifies the CONSTRUCTOR spans the entire array. gcc/testsuite/ChangeLog: PR c++/99700 * g++.dg/cpp2a/constexpr-init21.C: New test. --- gcc/cp/constexpr.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index c8d9dae..b74bbac 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -46,6 +46,7 @@ do { \ static HOST_WIDE_INT find_array_ctor_elt (tree ary, tree dindex, bool insert = false); +static int array_index_cmp (tree key, tree index); /* Returns true iff FUN is an instantiation of a constexpr function template or a defaulted constexpr function. */ @@ -2910,9 +2911,27 @@ reduced_constant_expression_p (tree t) /* An initialized vector would have a VECTOR_CST. */ return false; else if (cxx_dialect >= cxx20 - /* An ARRAY_TYPE doesn't have any TYPE_FIELDS. */ && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) - field = NULL_TREE; + { + /* There must be a valid constant initializer at every array + index. */ + tree min = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t))); + tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t))); + tree cursor = min; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), i, idx, val) + { + if (!reduced_constant_expression_p (val)) + return false; + if (array_index_cmp (cursor, idx) != 0) + return false; + if (TREE_CODE (idx) == RANGE_EXPR) + cursor = TREE_OPERAND (idx, 1); + cursor = int_const_binop (PLUS_EXPR, cursor, size_one_node); + } + if (find_array_ctor_elt (t, max) == -1) + return false; + goto ok; + } else if (cxx_dialect >= cxx20 && TREE_CODE (TREE_TYPE (t)) == UNION_TYPE) { @@ -2946,6 +2965,7 @@ reduced_constant_expression_p (tree t) for (; field; field = next_initializable_field (DECL_CHAIN (field))) if (!is_really_empty_class (TREE_TYPE (field), /*ignore_vptr*/false)) return false; +ok: if (CONSTRUCTOR_NO_CLEARING (t)) /* All the fields are initialized. */ CONSTRUCTOR_NO_CLEARING (t) = false; -- cgit v1.1 From 70f2bff43aadd2fcc0595bf9f4bab72647529655 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 14 Apr 2021 17:57:15 -0400 Subject: c++: ICE with bogus late return type [PR99803] Here we ICE when compiling this code in C++20, because we're trying to slam a 'typename' after the ->. The cp_parser_template_id call just before the spot I'm changing parsed A::template A as a BASELINK that contains a constructor, but make_typename_type crashes on that. This patch makes make_typename_type more robust instead of checking for is_overloaded_fn prior calling it. gcc/cp/ChangeLog: PR c++/99803 * decl.c (make_typename_type): Give an error and return when name is is_overloaded_fn. * parser.c (cp_parser_class_name): Don't check is_overloaded_fn before calling make_typename_type. gcc/testsuite/ChangeLog: PR c++/99803 * g++.dg/cpp2a/typename14.C: Don't expect particular error messages. * g++.dg/cpp2a/typename19.C: New test. --- gcc/cp/decl.c | 8 +++++++- gcc/cp/parser.c | 4 +--- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index d40b7a7..942eb31 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4055,6 +4055,12 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, error ("%qD used without template arguments", name); return error_mark_node; } + else if (is_overloaded_fn (name)) + { + if (complain & tf_error) + error ("%qD is a function, not a type", name); + return error_mark_node; + } gcc_assert (identifier_p (name)); gcc_assert (TYPE_P (context)); @@ -4066,7 +4072,7 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, error ("%q#T is not a class", context); return error_mark_node; } - + /* When the CONTEXT is a dependent type, NAME could refer to a dependent base class of CONTEXT. But look inside it anyway if CONTEXT is a currently open scope, in case it refers to a diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index dfc9b82..99eccf0 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -24730,9 +24730,7 @@ cp_parser_class_name (cp_parser *parser, decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p); /* If this is a typename, create a TYPENAME_TYPE. */ - if (typename_p - && decl != error_mark_node - && !is_overloaded_fn (decl)) + if (typename_p && decl != error_mark_node) { decl = make_typename_type (scope, decl, typename_type, /*complain=*/tf_error); -- cgit v1.1 From 35e8b38a91d9fb49a4759649576f15e76c129d99 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 16 Apr 2021 17:37:07 +0200 Subject: c++: Fix empty base stores in cxx_eval_store_expression [PR100111] In r11-6895 handling of empty bases has been fixed such that non-lval stores of empty classes are not added when the type of *valp doesn't match the type of the initializer, but as this testcase shows it is done only when *valp is non-NULL. If it is NULL, we still shouldn't add empty class constructors if the type of the constructor elt *valp points to doesn't match. 2021-04-16 Jakub Jelinek PR c++/100111 * constexpr.c (cxx_eval_store_expression): Don't add CONSTRUCTORs for empty classes into *valp when types don't match even when *valp is NULL. * g++.dg/cpp0x/constexpr-100111.C: New test. --- gcc/cp/constexpr.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index b74bbac..0fb0ab4 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5538,6 +5538,14 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, CONSTRUCTOR_NO_CLEARING (*valp) = CONSTRUCTOR_NO_CLEARING (init); } + else if (TREE_CODE (init) == CONSTRUCTOR + && !same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init), + type)) + { + /* See above on initialization of empty bases. */ + gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval); + return init; + } else *valp = init; -- cgit v1.1 From 8ae884c09fbba91e9cec391290ee4a2859e7ff41 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 17 Apr 2021 00:16:25 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b5c21bf..69f1927 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,48 @@ +2021-04-16 Jakub Jelinek + + PR c++/100111 + * constexpr.c (cxx_eval_store_expression): Don't add CONSTRUCTORs + for empty classes into *valp when types don't match even when *valp + is NULL. + +2021-04-16 Marek Polacek + + PR c++/99803 + * decl.c (make_typename_type): Give an error and return when + name is is_overloaded_fn. + * parser.c (cp_parser_class_name): Don't check is_overloaded_fn + before calling make_typename_type. + +2021-04-16 Patrick Palka + + PR c++/99700 + * constexpr.c (reduced_constant_expression_p): For array + CONSTRUCTORs, use a dedicated loop that additionally verifies + the CONSTRUCTOR spans the entire array. + +2021-04-16 Jakub Jelinek + + PR c++/99850 + * parser.c (cp_parser_constraint_requires_parens) : + If lambda_p, return pce_ok instead of pce_maybe_postfix. + +2021-04-16 Jakub Jelinek + + PR c++/99833 + * pt.c (extract_locals_r): When handling DECL_EXPR of a structured + binding, add to data.internal also all corresponding structured + binding decls. + +2021-04-16 Jason Merrill + + PR c++/100079 + * cp-tree.h (first_field): Declare. + * mangle.c (range_expr_nelts): New. + (write_expression): Improve class NTTP mangling. + * pt.c (get_template_parm_object): Clear TREE_HAS_CONSTRUCTOR. + * tree.c (zero_init_expr_p): Improve class NTTP handling. + * decl.c: Adjust comment. + 2021-04-15 Jason Merrill PR c++/80456 -- cgit v1.1 From 29d8838c5ecaf70ce552fea7639ec1f34adb2e04 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Mon, 19 Apr 2021 16:21:46 -0400 Subject: c++: ICE with concept defined in function [PR97536] This is an ICE-on-invalid, but I keep seeing it when reducing code so I'd like to fix it. We crash on template void forward() { concept C = true; } which breaks two requirements: [temp.concept]/1: A concept is a template ... [temp.concept]/3: A concept-definition shall inhabit a namespace scope. This patch adds a test that exercises broken code and fixes the ICE by checking that a concept-definition is defined at namespace scope. gcc/cp/ChangeLog: PR c++/97536 * decl.c (grokvardecl): Given an error when a concept is not defined at namespace scope. gcc/testsuite/ChangeLog: PR c++/97536 * g++.dg/concepts/diagnostic16.C: New test. --- gcc/cp/decl.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 942eb31..b81de8e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10365,6 +10365,12 @@ grokvardecl (tree type, "a non-template variable cannot be %"); return NULL_TREE; } + else if (!at_namespace_scope_p ()) + { + error_at (declspecs->locations[ds_concept], + "concept must be defined at namespace scope"); + return NULL_TREE; + } else DECL_DECLARED_CONCEPT_P (decl) = true; if (!same_type_ignoring_top_level_qualifiers_p (type, boolean_type_node)) -- cgit v1.1 From 6e81e015d91568fc3df3939623ae999e0681a0fc Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 20 Apr 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 69f1927..335018c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2021-04-19 Marek Polacek + + PR c++/97536 + * decl.c (grokvardecl): Given an error when a concept is not defined + at namespace scope. + 2021-04-16 Jakub Jelinek PR c++/100111 -- cgit v1.1 From 7f5deba1c21888aacedae93e9f324827073a1d1e Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 20 Apr 2021 00:50:49 -0400 Subject: c++: unexpanded pack in enum in lambda [PR100109] Another construct we need to look inside. gcc/cp/ChangeLog: PR c++/100109 * pt.c (find_parameter_packs_r): Look into enum initializers. gcc/testsuite/ChangeLog: PR c++/100109 * g++.dg/cpp0x/lambda/lambda-variadic14.C: New test. --- gcc/cp/pt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 19fdafa..7bcbe6d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -4066,12 +4066,18 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) return NULL_TREE; case TAG_DEFN: - /* Local class, need to look through the whole definition. */ t = TREE_TYPE (t); if (CLASS_TYPE_P (t)) + /* Local class, need to look through the whole definition. */ for (tree bb : BINFO_BASE_BINFOS (TYPE_BINFO (t))) cp_walk_tree (&BINFO_TYPE (bb), &find_parameter_packs_r, ppd, ppd->visited); + else + /* Enum, look at the values. */ + for (tree l = TYPE_VALUES (t); l; l = TREE_CHAIN (l)) + cp_walk_tree (&DECL_INITIAL (TREE_VALUE (l)), + &find_parameter_packs_r, + ppd, ppd->visited); return NULL_TREE; case FUNCTION_TYPE: -- cgit v1.1 From be8aad8d73f47e2581c873ba1069489e071c2a86 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 21 Apr 2021 00:16:23 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 335018c..2bfd78b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2021-04-20 Jason Merrill + + PR c++/100109 + * pt.c (find_parameter_packs_r): Look into enum initializers. + 2021-04-19 Marek Polacek PR c++/97536 -- cgit v1.1 From df0581a4aff45e73ba7b73df7b98ba492bdc28a8 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 18 Feb 2021 12:58:39 +0100 Subject: Support LABEL_DECL in %qD directive. gcc/cp/ChangeLog: * error.c (dump_decl): Support anonymous labels. gcc/ChangeLog: * tree-cfg.c (gimple_verify_flow_info): Use qD instead of print_generic_expr. --- gcc/cp/error.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/error.c b/gcc/cp/error.c index ff4ae6f..c88d174 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1362,7 +1362,10 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags) break; case LABEL_DECL: - pp_cxx_tree_identifier (pp, DECL_NAME (t)); + if (DECL_NAME (t)) + pp_cxx_tree_identifier (pp, DECL_NAME (t)); + else + dump_generic_node (pp, t, 0, TDF_SLIM, false); break; case CONST_DECL: -- cgit v1.1 From 9b6360b83cf5c684422c42301faee3a79ac42dc1 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 21 Apr 2021 13:27:08 +0200 Subject: Use flags in dump_decl. gcc/cp/ChangeLog: * error.c (dump_decl): Use flags in dump_generic_node call. --- gcc/cp/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/error.c b/gcc/cp/error.c index c88d174..c4ae76f 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1365,7 +1365,7 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags) if (DECL_NAME (t)) pp_cxx_tree_identifier (pp, DECL_NAME (t)); else - dump_generic_node (pp, t, 0, TDF_SLIM, false); + dump_generic_node (pp, t, 0, flags | TDF_SLIM, false); break; case CONST_DECL: -- cgit v1.1 From d2218b045e0ef52df33230e137f80722c2a82a8a Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 21 Apr 2021 13:30:03 +0200 Subject: Revert "Use flags in dump_decl." This reverts commit 9b6360b83cf5c684422c42301faee3a79ac42dc1. --- gcc/cp/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/error.c b/gcc/cp/error.c index c4ae76f..c88d174 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1365,7 +1365,7 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags) if (DECL_NAME (t)) pp_cxx_tree_identifier (pp, DECL_NAME (t)); else - dump_generic_node (pp, t, 0, flags | TDF_SLIM, false); + dump_generic_node (pp, t, 0, TDF_SLIM, false); break; case CONST_DECL: -- cgit v1.1 From 001c63d15e31bc0a1545426d889a0b9f671b4961 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 20 Apr 2021 12:16:04 -0400 Subject: c++: Don't allow defining types in enum-base [PR96380] In r11-2064 I made cp_parser_enum_specifier commit to tentative parse when seeing a '{'. That still looks like the correct thing to do, but it caused an ICE-on-invalid as well as accepts-invalid. When we have something sneaky like this, which is broken in multiple ways: template enum struct c : union enum struct c { e = b, f = a }; we parse the "enum struct c" part (that's OK) and then we see that we have an enum-base, so we consume ':' and then parse the type-specifier that follows the :. "union enum" is clearly invalid, but we're still parsing tentatively and we parse everything up to the ;, and then throw away the underlying type. We parsed everything because we were tricked into parsing an enum-specifier in an enum-base of another enum-specifier! Not good. Since the grammar for enum-base doesn't allow a defining-type-specifier, only a type-specifier, we should set type_definition_forbidden_message which fixes all the problems in this PR. gcc/cp/ChangeLog: PR c++/96380 * parser.c (cp_parser_enum_specifier): Don't allow defining types in enum-base. gcc/testsuite/ChangeLog: PR c++/96380 * g++.dg/cpp0x/enum_base4.C: New test. * g++.dg/cpp0x/enum_base5.C: New test. --- gcc/cp/parser.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 99eccf0..fba516e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -19942,6 +19942,10 @@ cp_parser_enum_specifier (cp_parser* parser) /* Consume the `:'. */ cp_lexer_consume_token (parser->lexer); + auto tdf + = make_temp_override (parser->type_definition_forbidden_message, + G_("types may not be defined in enum-base")); + /* Parse the type-specifier-seq. */ cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE, /*is_declaration=*/false, -- cgit v1.1 From c1ef0c9234c29c33397b7687ba54c1221fcbcb6b Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 22 Apr 2021 00:16:32 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2bfd78b..89cb361 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,24 @@ +2021-04-21 Marek Polacek + + PR c++/96380 + * parser.c (cp_parser_enum_specifier): Don't allow defining + types in enum-base. + +2021-04-21 Martin Liska + + Revert: + 2021-04-21 Martin Liska + + * error.c (dump_decl): Use flags in dump_generic_node call. + +2021-04-21 Martin Liska + + * error.c (dump_decl): Use flags in dump_generic_node call. + +2021-04-21 Martin Liska + + * error.c (dump_decl): Support anonymous labels. + 2021-04-20 Jason Merrill PR c++/100109 -- cgit v1.1 From 244dfb95119106e9267f37583caac565c39eb0ec Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 20 Apr 2021 20:24:09 -0400 Subject: c++: Prevent bogus -Wtype-limits warning with NTTP [PR100161] Recently, we made sure that we never call value_dependent_expression_p on an expression that isn't potential_constant_expression. That caused this bogus warning with a non-type template parameter, something that users don't want to see. The problem is that in tsubst_copy_and_build/LE_EXPR 't' is "i < n", which, due to 'i', is not p_c_e, therefore we call t_d_e_p. But the type of 'n' isn't dependent, so we think the whole 't' expression is not dependent. It seems we need to test both op0 and op1 separately to suppress this warning. gcc/cp/ChangeLog: PR c++/100161 * pt.c (tsubst_copy_and_build) : Test op0 and op1 separately for value- or type-dependence. gcc/testsuite/ChangeLog: PR c++/100161 * g++.dg/warn/Wtype-limits6.C: New test. --- gcc/cp/pt.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7bcbe6d..8d64fef 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -19906,15 +19906,21 @@ tsubst_copy_and_build (tree t, case MEMBER_REF: case DOTSTAR_EXPR: { - /* If T was type-dependent, suppress warnings that depend on the range - of the types involved. */ - ++processing_template_decl; - const bool was_dep = (potential_constant_expression (t) - ? value_dependent_expression_p (t) - : type_dependent_expression_p (t)); - --processing_template_decl; - tree op0 = RECUR (TREE_OPERAND (t, 0)); - tree op1 = RECUR (TREE_OPERAND (t, 1)); + /* If either OP0 or OP1 was value- or type-dependent, suppress + warnings that depend on the range of the types involved. */ + tree op0 = TREE_OPERAND (t, 0); + tree op1 = TREE_OPERAND (t, 1); + auto dep_p = [](tree t) { + ++processing_template_decl; + bool r = (potential_constant_expression (t) + ? value_dependent_expression_p (t) + : type_dependent_expression_p (t)); + --processing_template_decl; + return r; + }; + const bool was_dep = dep_p (op0) || dep_p (op1); + op0 = RECUR (op0); + op1 = RECUR (op1); warning_sentinel s1(warn_type_limits, was_dep); warning_sentinel s2(warn_div_by_zero, was_dep); -- cgit v1.1 From e3948473e927a7c3197ce1a63628fe427f15f6c6 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 23 Apr 2021 00:16:25 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 89cb361..7233833 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2021-04-22 Marek Polacek + + PR c++/100161 + * pt.c (tsubst_copy_and_build) : Test op0 and + op1 separately for value- or type-dependence. + 2021-04-21 Marek Polacek PR c++/96380 -- cgit v1.1 From cbca62831cb7c1c7c20d67fcf929f156b09923bf Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 12 Mar 2021 14:32:07 +0100 Subject: c++: Use STATIC_ASSERT for OVL_OP_MAX. gcc/cp/ChangeLog: * cp-tree.h (STATIC_ASSERT): Prefer static assert. * lex.c (init_operators): Remove run-time check. --- gcc/cp/cp-tree.h | 3 +++ gcc/cp/lex.c | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 23a77a2..cb254e0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5922,6 +5922,9 @@ enum ovl_op_code { OVL_OP_MAX }; +/* Make sure it fits in lang_decl_fn::ovl_op_code. */ +STATIC_ASSERT (OVL_OP_MAX < (1 << 6)); + struct GTY(()) ovl_op_info_t { /* The IDENTIFIER_NODE for the operator. */ tree identifier; diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index 73e14b8..43abd01 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -166,8 +166,6 @@ init_operators (void) if (op_ptr->name) { - /* Make sure it fits in lang_decl_fn::operator_code. */ - gcc_checking_assert (op_ptr->ovl_op_code < (1 << 6)); tree ident = set_operator_ident (op_ptr); if (unsigned index = IDENTIFIER_CP_INDEX (ident)) { -- cgit v1.1 From 5f8aed72e76970d2c6fa06fb23fdaa47660555b0 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 23 Apr 2021 08:28:58 -0400 Subject: c++: Refine enum direct-list-initialization [CWG2374] This implements the wording changes of CWG2374, which clarifies the wording of P0138 to forbid e.g. direct-list-initialization of a scoped enumeration from a different scoped enumeration. gcc/cp/ChangeLog: DR 2374 * decl.c (is_direct_enum_init): Check the implicit convertibility requirement added by CWG 2374. gcc/testsuite/ChangeLog: DR 2374 * g++.dg/cpp1z/direct-enum-init2.C: New test. --- gcc/cp/decl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b81de8e..60dc2bf 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6191,7 +6191,13 @@ is_direct_enum_init (tree type, tree init) && ENUM_FIXED_UNDERLYING_TYPE_P (type) && TREE_CODE (init) == CONSTRUCTOR && CONSTRUCTOR_IS_DIRECT_INIT (init) - && CONSTRUCTOR_NELTS (init) == 1) + && CONSTRUCTOR_NELTS (init) == 1 + /* DR 2374: The single element needs to be implicitly + convertible to the underlying type of the enum. */ + && can_convert_arg (ENUM_UNDERLYING_TYPE (type), + TREE_TYPE (CONSTRUCTOR_ELT (init, 0)->value), + CONSTRUCTOR_ELT (init, 0)->value, + LOOKUP_IMPLICIT, tf_none)) return true; return false; } -- cgit v1.1 From 87fc34a461cf362947a430d8a241f653fd83bc7b Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 23 Apr 2021 08:47:02 -0400 Subject: c++: Fix pretty printing pointer to function type [PR98767] When pretty printing a pointer to function type, pp_cxx_parameter_declaration_clause ends up always outputting an empty function parameter list because the loop that outputs the list iterates over 'args' instead of 'types', and 'args' is empty when a FUNCTION_TYPE is passed to this routine (as opposed to a FUNCTION_DECL). This patch fixes this by making the loop iterate over 'types' instead. This patch also moves the retrofitted chain-of-PARM_DECLs printing from here to pp_cxx_requires_expr, the only caller that uses it. Doing so lets us easily output the trailing '...' in the parameter list of a variadic function, which this patch also implements. gcc/cp/ChangeLog: PR c++/98767 * cxx-pretty-print.c (pp_cxx_parameter_declaration_clause): Adjust parameter list loop to iterate over 'types' instead of 'args'. Output the trailing '...' for a variadic function. Remove PARM_DECL support. (pp_cxx_requires_expr): Pretty print the parameter list directly instead of going through pp_cxx_parameter_declaration_clause. gcc/testsuite/ChangeLog: PR c++/98767 * g++.dg/concepts/diagnostic17.C: New test. --- gcc/cp/cxx-pretty-print.c | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index a22eea5..3709d0f 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -1537,38 +1537,36 @@ pp_cxx_parameter_declaration (cxx_pretty_printer *pp, tree t) static void pp_cxx_parameter_declaration_clause (cxx_pretty_printer *pp, tree t) { - tree args; - tree types; - bool abstract; - - // For a requires clause or the explicit printing of a parameter list - // we expect T to be a chain of PARM_DECLs. Otherwise, the list of - // args and types are taken from the function decl T. - if (TREE_CODE (t) == PARM_DECL) + gcc_assert (FUNC_OR_METHOD_TYPE_P (t) || TREE_CODE (t) == FUNCTION_DECL); + tree types, args; + if (TYPE_P (t)) { - args = t; - types = t; - abstract = false; + types = TYPE_ARG_TYPES (t); + args = NULL_TREE; } else { - bool type_p = TYPE_P (t); - args = type_p ? NULL : FUNCTION_FIRST_USER_PARM (t); - types = type_p ? TYPE_ARG_TYPES (t) : FUNCTION_FIRST_USER_PARMTYPE (t); - abstract = args == NULL || pp->flags & pp_c_flag_abstract; + types = FUNCTION_FIRST_USER_PARMTYPE (t); + args = FUNCTION_FIRST_USER_PARM (t); } - bool first = true; + bool abstract = !args || (pp->flags & pp_c_flag_abstract); /* Skip artificial parameter for non-static member functions. */ if (TREE_CODE (t) == METHOD_TYPE) types = TREE_CHAIN (types); + bool first = true; pp_cxx_left_paren (pp); - for (; args; args = TREE_CHAIN (args), types = TREE_CHAIN (types)) + for (; types != void_list_node; types = TREE_CHAIN (types)) { if (!first) pp_cxx_separate_with (pp, ','); first = false; + if (!types) + { + pp_cxx_ws_string (pp, "..."); + break; + } pp_cxx_parameter_declaration (pp, abstract ? TREE_VALUE (types) : args); if (!abstract && pp->flags & pp_cxx_flag_default_argument) { @@ -1577,6 +1575,8 @@ pp_cxx_parameter_declaration_clause (cxx_pretty_printer *pp, tree t) pp_cxx_whitespace (pp); pp->assignment_expression (TREE_PURPOSE (types)); } + if (!abstract) + args = TREE_CHAIN (args); } pp_cxx_right_paren (pp); } @@ -2775,9 +2775,18 @@ void pp_cxx_requires_expr (cxx_pretty_printer *pp, tree t) { pp_string (pp, "requires"); - if (tree parms = TREE_OPERAND (t, 0)) + if (tree parms = REQUIRES_EXPR_PARMS (t)) { - pp_cxx_parameter_declaration_clause (pp, parms); + bool first = true; + pp_cxx_left_paren (pp); + for (; parms; parms = TREE_CHAIN (parms)) + { + if (!first) + pp_cxx_separate_with (pp, ',' ); + first = false; + pp_cxx_parameter_declaration (pp, parms); + } + pp_cxx_right_paren (pp); pp_cxx_whitespace (pp); } pp_cxx_requirement_body (pp, TREE_OPERAND (t, 1)); -- cgit v1.1 From 05ec629f05646837301820b89354a64673185224 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 24 Apr 2021 00:16:37 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7233833..d64cdce 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,24 @@ +2021-04-23 Patrick Palka + + PR c++/98767 + * cxx-pretty-print.c (pp_cxx_parameter_declaration_clause): + Adjust parameter list loop to iterate over 'types' instead of + 'args'. Output the trailing '...' for a variadic function. + Remove PARM_DECL support. + (pp_cxx_requires_expr): Pretty print the parameter list directly + instead of going through pp_cxx_parameter_declaration_clause. + +2021-04-23 Patrick Palka + + DR 2374 + * decl.c (is_direct_enum_init): Check the implicit + convertibility requirement added by CWG 2374. + +2021-04-23 Martin Liska + + * cp-tree.h (STATIC_ASSERT): Prefer static assert. + * lex.c (init_operators): Remove run-time check. + 2021-04-22 Marek Polacek PR c++/100161 -- cgit v1.1 From 5f1a2cb9c2dc09eed53da5d5787d14bec700b10b Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Sat, 24 Apr 2021 00:01:42 -0400 Subject: c++: Hard error with tentative parse and CTAD [PR87709] When parsing e.g. the operand of sizeof, where both types and expressions are accepted, if during the tentative type parse we encounter an unexpected template placeholder, we must simulate an error rather than issue a real error because the expression parse can still succeed. gcc/cp/ChangeLog: PR c++/87709 * parser.c (cp_parser_type_id_1): If we see a template placeholder, first try simulating an error before issuing a real error. gcc/testsuite/ChangeLog: PR c++/87709 * g++.dg/cpp1z/class-deduction86.C: New test. --- gcc/cp/parser.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index fba516e..e1b1617 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -23270,10 +23270,13 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags, location_t loc = type_specifier_seq.locations[ds_type_spec]; if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) { - error_at (loc, "missing template arguments after %qT", - auto_node); - inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", - tmpl); + if (!cp_parser_simulate_error (parser)) + { + error_at (loc, "missing template arguments after %qT", + auto_node); + inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", + tmpl); + } } else if (parser->in_template_argument_list_p) error_at (loc, "%qT not permitted in template argument", -- cgit v1.1 From bcd77b7b9f35bd5b559ed593c3b3e346c1e6f364 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Sat, 24 Apr 2021 00:14:29 -0400 Subject: c++: do_class_deduction and dependent init [PR93383] Here we're crashing during CTAD with a dependent initializer (performed from convert_template_argument) because one of the initializer's elements has an empty TREE_TYPE, which ends up making resolve_args unhappy. Besides the case where we're initializing one template placeholder from another, which is already specifically handled earlier in do_class_deduction, it seems we can't in general correctly resolve a template placeholder using a dependent initializer, so this patch makes the function just punt until instantiation time instead. gcc/cp/ChangeLog: PR c++/89565 PR c++/93383 PR c++/95291 PR c++/99200 PR c++/99683 * pt.c (do_class_deduction): Punt if the initializer is type-dependent. gcc/testsuite/ChangeLog: PR c++/89565 PR c++/93383 PR c++/95291 PR c++/99200 PR c++/99683 * g++.dg/cpp2a/nontype-class39.C: Remove dg-ice directive. * g++.dg/cpp2a/nontype-class45.C: New test. * g++.dg/cpp2a/nontype-class46.C: New test. * g++.dg/cpp2a/nontype-class47.C: New test. * g++.dg/cpp2a/nontype-class48.C: New test. --- gcc/cp/pt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8d64fef..8c3c814 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -29368,6 +29368,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init, return error_mark_node; } + /* Wait until the initializer is non-dependent. */ + if (type_dependent_expression_p (init)) + return ptype; + tree type = TREE_TYPE (tmpl); bool try_list_ctor = false; -- cgit v1.1 From 502ef97c4f442777e5f61c506d17f8776a69b207 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 25 Apr 2021 00:16:26 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d64cdce..b213029 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,20 @@ +2021-04-24 Patrick Palka + + PR c++/89565 + PR c++/93383 + PR c++/95291 + PR c++/99200 + PR c++/99683 + * pt.c (do_class_deduction): Punt if the initializer is + type-dependent. + +2021-04-24 Patrick Palka + + PR c++/87709 + * parser.c (cp_parser_type_id_1): If we see a template + placeholder, first try simulating an error before issuing + a real error. + 2021-04-23 Patrick Palka PR c++/98767 -- cgit v1.1 From 0120cd9382728fdc99d4cfdcb72cd0f55aca2ce3 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 26 Apr 2021 17:30:39 -0400 Subject: c++: constexpr pointer indirection with negative offset [PR100209] During constexpr evaluation, a base-to-derived conversion may yield an expression like (Derived*)(&D.2217.D.2106 p+ -4) where D.2217 is the derived object and D.2106 is the base. But cxx_fold_indirect_ref doesn't know how to resolve an INDIRECT_REF thereof to just D.2217, because it doesn't handle POINTER_PLUS_EXPR of a COMPONENT_REF with negative offset well: when the offset N is positive, it knows that '&x p+ N' is equivalent to '&x.f p+ (N - bytepos(f))', but it doesn't know about the reverse transformation, that '&x.f p+ N' is equivalent to '&x p+ (N + bytepos(f))' when N is negative, which is important for resolving such base-to-derived conversions and for accessing subobjects backwards. This patch teaches cxx_fold_indirect_ref this reverse transformation. gcc/cp/ChangeLog: PR c++/100209 * constexpr.c (cxx_fold_indirect_ref): Try to canonicalize the object/offset pair for a POINTER_PLUS_EXPR of a COMPONENT_REF with a negative offset into one whose offset is nonnegative before calling cxx_fold_indirect_ref_1. gcc/testsuite/ChangeLog: PR c++/100209 * g++.dg/cpp1y/constexpr-base1.C: New test. * g++.dg/cpp1y/constexpr-ptrsub1.C: New test. --- gcc/cp/constexpr.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 0fb0ab4..fa7eaed 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -4894,12 +4894,26 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, && tree_fits_uhwi_p (TREE_OPERAND (sub, 1))) { tree op00 = TREE_OPERAND (sub, 0); - tree op01 = TREE_OPERAND (sub, 1); + tree off = TREE_OPERAND (sub, 1); STRIP_NOPS (op00); if (TREE_CODE (op00) == ADDR_EXPR) - return cxx_fold_indirect_ref_1 (ctx, loc, type, TREE_OPERAND (op00, 0), - tree_to_uhwi (op01), empty_base); + { + tree obj = TREE_OPERAND (op00, 0); + while (TREE_CODE (obj) == COMPONENT_REF + && tree_int_cst_sign_bit (off)) + { + /* Canonicalize this object/offset pair by iteratively absorbing + the innermost component into the offset until the offset is + nonnegative, so that cxx_fold_indirect_ref_1 can identify + more folding opportunities. */ + tree field = TREE_OPERAND (obj, 1); + off = int_const_binop (PLUS_EXPR, off, byte_position (field)); + obj = TREE_OPERAND (obj, 0); + } + return cxx_fold_indirect_ref_1 (ctx, loc, type, obj, + tree_to_uhwi (off), empty_base); + } } /* *(foo *)fooarrptr => (*fooarrptr)[0] */ else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE -- cgit v1.1 From c0fa3f2fb365144b3a059920aeaf6ff37db1177d Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 27 Apr 2021 00:16:30 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b213029..ec6e1d6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2021-04-26 Patrick Palka + + PR c++/100209 + * constexpr.c (cxx_fold_indirect_ref): Try to canonicalize the + object/offset pair for a POINTER_PLUS_EXPR of a COMPONENT_REF + with a negative offset into one whose offset is nonnegative + before calling cxx_fold_indirect_ref_1. + 2021-04-24 Patrick Palka PR c++/89565 -- cgit v1.1 From 37d2b98100cefcb9d312d379473c12aa6d61fc62 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 27 Apr 2021 14:18:25 -0400 Subject: c++: Fix Bases(args...)... base initialization [PR88580] When substituting into the arguments of a base initializer pack expansion, tsubst_initializer_list uses a dummy EXPR_PACK_EXPANSION in order to expand an initializer such as Bases(args)... into Bases#{0}(args#{0}) and so on. But when an argument inside the base initializer is itself a pack expansion, as in Bases(args...)..., the argument is already an EXPR_PACK_EXPANSION so we don't need to wrap it. It's also independent from the outer expansion of Bases, so we need to "multiplicatively" append the expansion of args... onto the argument list of each expanded base. gcc/cp/ChangeLog: PR c++/88580 * pt.c (tsubst_initializer_list): Correctly handle the case where an argument inside a base initializer pack expansion is itself a pack expansion. gcc/testsuite/ChangeLog: PR c++/88580 * g++.dg/cpp0x/variadic182.C: New test. --- gcc/cp/pt.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8c3c814..eaf4665 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -26389,9 +26389,16 @@ tsubst_initializer_list (tree t, tree argvec) tree expanded_exprs; /* Expand the argument. */ - SET_PACK_EXPANSION_PATTERN (expr, TREE_VALUE (arg)); + tree value; + if (TREE_CODE (TREE_VALUE (arg)) == EXPR_PACK_EXPANSION) + value = TREE_VALUE (arg); + else + { + value = expr; + SET_PACK_EXPANSION_PATTERN (value, TREE_VALUE (arg)); + } expanded_exprs - = tsubst_pack_expansion (expr, argvec, + = tsubst_pack_expansion (value, argvec, tf_warning_or_error, NULL_TREE); if (expanded_exprs == error_mark_node) @@ -26400,12 +26407,17 @@ tsubst_initializer_list (tree t, tree argvec) /* Prepend each of the expanded expressions to the corresponding TREE_LIST in EXPANDED_ARGUMENTS. */ for (i = 0; i < len; i++) - { - TREE_VEC_ELT (expanded_arguments, i) = - tree_cons (NULL_TREE, - TREE_VEC_ELT (expanded_exprs, i), - TREE_VEC_ELT (expanded_arguments, i)); - } + if (TREE_CODE (TREE_VALUE (arg)) == EXPR_PACK_EXPANSION) + for (int j = 0; j < TREE_VEC_LENGTH (expanded_exprs); j++) + TREE_VEC_ELT (expanded_arguments, i) + = tree_cons (NULL_TREE, + TREE_VEC_ELT (expanded_exprs, j), + TREE_VEC_ELT (expanded_arguments, i)); + else + TREE_VEC_ELT (expanded_arguments, i) + = tree_cons (NULL_TREE, + TREE_VEC_ELT (expanded_exprs, i), + TREE_VEC_ELT (expanded_arguments, i)); } in_base_initializer = 0; -- cgit v1.1 From 37846c42f1f5ac4d9ba190d49c4373673c89c8b5 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 23 Apr 2021 16:41:35 -0400 Subject: c++: -Wdeprecated-copy and using operator= [PR92145] For the purpose of [depr.impldec] "if the class has a user-declared copy assignment operator", an operator= brought in from a base class with 'using' may be a copy-assignment operator, but it isn't a copy-assignment operator for the derived class. gcc/cp/ChangeLog: PR c++/92145 * class.c (classtype_has_depr_implicit_copy): Check DECL_CONTEXT of operator=. gcc/testsuite/ChangeLog: PR c++/92145 * g++.dg/cpp0x/depr-copy3.C: New test. --- gcc/cp/class.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 90b3438..2cf527e 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5670,7 +5670,8 @@ classtype_has_depr_implicit_copy (tree t) iter; ++iter) { tree fn = *iter; - if (user_provided_p (fn) && copy_fn_p (fn)) + if (DECL_CONTEXT (fn) == t + && user_provided_p (fn) && copy_fn_p (fn)) return fn; } -- cgit v1.1 From 8f54dd61e79842eebf678571b9987bda7502f3aa Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 28 Apr 2021 00:16:36 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ec6e1d6..ca8382f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2021-04-27 Jason Merrill + + PR c++/92145 + * class.c (classtype_has_depr_implicit_copy): Check DECL_CONTEXT + of operator=. + +2021-04-27 Patrick Palka + + PR c++/88580 + * pt.c (tsubst_initializer_list): Correctly handle the case + where an argument inside a base initializer pack expansion is + itself a pack expansion. + 2021-04-26 Patrick Palka PR c++/100209 -- cgit v1.1 From ea3d2e3c164cb4a32f5c82aa49693de260db3501 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 27 Apr 2021 11:37:30 +0200 Subject: c++: Remove #error for release builds * module.cc: Remove #error that triggers if DEV-PHASE is empty. --- gcc/cp/module.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index ab8b1f1..02c19f5 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -194,8 +194,6 @@ Classes used: #define MODULE_MINOR(V) ((V) % 10000) #define EXPERIMENT(A,B) (IS_EXPERIMENTAL (MODULE_VERSION) ? (A) : (B)) #ifndef MODULE_VERSION -// Be sure you're ready! Remove #error this before release! -#error "Shtopp! What are you doing? This is not ready yet." #include "bversion.h" #define MODULE_VERSION (BUILDING_GCC_MAJOR * 10000U + BUILDING_GCC_MINOR) #elif !IS_EXPERIMENTAL (MODULE_VERSION) -- cgit v1.1 From e4ff4ffb43d3d8520f1c106e04421f2e6a021c39 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 29 Apr 2021 00:17:01 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ca8382f..a093657 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,7 @@ +2021-04-28 Jakub Jelinek + + * module.cc: Remove #error that triggers if DEV-PHASE is empty. + 2021-04-27 Jason Merrill PR c++/92145 -- 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') 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 efeca0ac4155b76ce713155f190422aac20537c5 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 29 Apr 2021 13:43:00 -0400 Subject: c++: Overeager use of deleted function before ADL [PR68942] Here, at template definition time, ordinary name lookup for 'foo(t)' finds only the deleted function, and so we form a CALL_EXPR thereof. Later at instantiation time, when initially substituting into this CALL_EXPR with T=N::A, we end up calling mark_used on this deleted function (since it's the only function in the overload set), triggering a bogus "use of deleted function error", before we get to augment the overload set via ADL. This patch fixes this issue by using the tf_conv flag to disable mark_used during the initial substitution into the callee of a CALL_EXPR when KOENIG_P, since at this point we're still figuring out which functions are candidates. gcc/cp/ChangeLog: PR c++/68942 * pt.c (tsubst_copy_and_build) : When KOENIG_P, set tf_conv during the initial substitution into the function. gcc/testsuite/ChangeLog: PR c++/68942 * g++.dg/template/koenig12.C: New test. --- gcc/cp/pt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index eaf4665..4e9b40f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20232,7 +20232,11 @@ tsubst_copy_and_build (tree t, /* Avoid error about taking the address of a constructor. */ function = TREE_OPERAND (function, 0); - function = tsubst_copy_and_build (function, args, complain, + /* When KOENIG_P, we don't want to mark_used the callee before + augmenting the overload set via ADL, so during this initial + substitution we disable mark_used by setting tf_conv (68942). */ + function = tsubst_copy_and_build (function, args, + complain | (koenig_p * tf_conv), in_decl, !qualified_p, integral_constant_expression_p); -- 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/cp-tree.h | 6 ++++-- gcc/cp/pt.c | 2 +- gcc/cp/semantics.c | 8 ++++++-- gcc/cp/tree.c | 8 ++------ gcc/cp/typeck2.c | 6 ++++++ 5 files changed, 19 insertions(+), 11 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index cb254e0..e80902a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4407,7 +4407,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) When appearing in a SAVE_EXPR, it means that underneath is a call to a constructor. - When appearing in a CONSTRUCTOR, the expression is a + When appearing in a CONSTRUCTOR, the expression is an unconverted compound literal. When appearing in a FIELD_DECL, it means that this field @@ -4419,7 +4419,9 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) (TREE_CODE (NODE) == CONSTRUCTOR && TREE_TYPE (NODE) == init_list_type_node) /* True if NODE is a compound-literal, i.e., a brace-enclosed - initializer cast to a particular type. */ + initializer cast to a particular type. This is mostly only set during + template parsing; once the initializer has been digested into an actual + value of the type, the expression is represented by a TARGET_EXPR. */ #define COMPOUND_LITERAL_P(NODE) \ (TREE_CODE (NODE) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (NODE)) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4e9b40f..fc5065b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -7157,7 +7157,7 @@ get_template_parm_object (tree expr, tsubst_flags_t complain) return error_mark_node; /* This is no longer a compound literal. */ - TREE_HAS_CONSTRUCTOR (expr) = 0; + gcc_assert (!TREE_HAS_CONSTRUCTOR (expr)); tree name = mangle_template_parm_object (expr); tree decl = get_global_binding (name); 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; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index a8bfd5f..3a20cd3 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -4684,13 +4684,9 @@ zero_init_expr_p (tree t) return null_member_pointer_value_p (t); if (TREE_CODE (t) == CONSTRUCTOR) { - if (CONSTRUCTOR_IS_DEPENDENT (t) + if (COMPOUND_LITERAL_P (t) || BRACE_ENCLOSED_INITIALIZER_P (t)) - /* Undigested, conversions might change the zeroness. - - Other COMPOUND_LITERAL_P in template context are also undigested, - but there isn't currently a way to distinguish between them and - COMPOUND_LITERAL_P from non-template context that are digested. */ + /* Undigested, conversions might change the zeroness. */ return false; for (constructor_elt &elt : CONSTRUCTOR_ELTS (t)) { diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 4e9632f..ce3016c 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -818,6 +818,12 @@ store_init_value (tree decl, tree init, vec** cleanups, int flags) /* Handle aggregate NSDMI in non-constant initializers, too. */ value = replace_placeholders (value, decl); + /* A COMPOUND_LITERAL_P CONSTRUCTOR is the syntactic form; by the time we get + here it should have been digested into an actual value for the type. */ + gcc_checking_assert (TREE_CODE (value) != CONSTRUCTOR + || processing_template_decl + || !TREE_HAS_CONSTRUCTOR (value)); + /* If the initializer is not a constant, fill in DECL_INITIAL with the bits that are constant, and then return an expression that will perform the dynamic initialization. */ -- 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/cp-tree.h | 5 +++-- gcc/cp/parser.c | 15 +++++++++++---- gcc/cp/semantics.c | 10 ---------- 3 files changed, 14 insertions(+), 16 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e80902a..d3639e3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5482,9 +5482,10 @@ class cp_evaluated public: int uneval; int inhibit; - cp_evaluated () + cp_evaluated (bool reset = true) : uneval(cp_unevaluated_operand), inhibit(c_inhibit_evaluation_warnings) - { cp_unevaluated_operand = c_inhibit_evaluation_warnings = 0; } + { if (reset) + cp_unevaluated_operand = c_inhibit_evaluation_warnings = 0; } ~cp_evaluated () { cp_unevaluated_operand = uneval; c_inhibit_evaluation_warnings = inhibit; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index e1b1617..9603a1e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2163,7 +2163,7 @@ static enum tree_code cp_parser_assignment_operator_opt static cp_expr cp_parser_expression (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = false); static cp_expr cp_parser_constant_expression - (cp_parser *, bool = false, bool * = NULL, bool = false); + (cp_parser *, int = 0, bool * = NULL, bool = false); static cp_expr cp_parser_builtin_offsetof (cp_parser *); static cp_expr cp_parser_lambda_expression @@ -10374,13 +10374,15 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk, If ALLOW_NON_CONSTANT_P a non-constant expression is silently accepted. If ALLOW_NON_CONSTANT_P is true and the expression is not constant, *NON_CONSTANT_P is set to TRUE. If ALLOW_NON_CONSTANT_P - is false, NON_CONSTANT_P should be NULL. If STRICT_P is true, + is false, NON_CONSTANT_P should be NULL. If ALLOW_NON_CONSTANT_P is + greater than 1, this isn't really a constant-expression, only a + potentially constant-evaluated expression. If STRICT_P is true, only parse a conditional-expression, otherwise parse an assignment-expression. See below for rationale. */ static cp_expr cp_parser_constant_expression (cp_parser* parser, - bool allow_non_constant_p, + int allow_non_constant_p, bool *non_constant_p, bool strict_p) { @@ -10416,6 +10418,11 @@ cp_parser_constant_expression (cp_parser* parser, parser->allow_non_integral_constant_expression_p = (allow_non_constant_p || cxx_dialect >= cxx11); parser->non_integral_constant_expression_p = false; + + /* A manifestly constant-evaluated expression is evaluated even in an + unevaluated operand. */ + cp_evaluated ev (/*reset if*/allow_non_constant_p <= 1); + /* Although the grammar says "conditional-expression", when not STRICT_P, we parse an "assignment-expression", which also permits "throw-expression" and the use of assignment operators. In the case @@ -24239,7 +24246,7 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p) { initializer = cp_parser_constant_expression (parser, - /*allow_non_constant_p=*/true, + /*allow_non_constant_p=*/2, non_constant_p); } else 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 58a92b789a77cdade1f41800efebf6e0686f9982 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 10 Apr 2021 14:00:15 -0400 Subject: c++: ICE with anonymous union [PR97974] While working on the GCC 11 patch, it occurred to me that we could move the errors about invalid members from finish_struct_anon_r to here, so we properly get a diagnostic in g++.law/union4.C. gcc/cp/ChangeLog: PR c++/97974 * class.c (finish_struct_anon_r): Drop complain parm. Remove non-field diagnostic. (finish_struct_anon): Adjust. * decl.c (fixup_anonymous_aggr): Move non-field diagnostic here. gcc/testsuite/ChangeLog: PR c++/97974 * g++.old-deja/g++.law/union4.C: Add expected diagnostic. --- gcc/cp/class.c | 34 +++------------------------------- gcc/cp/decl.c | 45 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 36 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 2cf527e..d693b43 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3023,7 +3023,7 @@ warn_hidden (tree t) /* Recursive helper for finish_struct_anon. */ static void -finish_struct_anon_r (tree field, bool complain) +finish_struct_anon_r (tree field) { for (tree elt = TYPE_FIELDS (TREE_TYPE (field)); elt; elt = DECL_CHAIN (elt)) { @@ -3039,34 +3039,6 @@ finish_struct_anon_r (tree field, bool complain) || TYPE_UNNAMED_P (TREE_TYPE (elt)))) continue; - if (complain - && (TREE_CODE (elt) != FIELD_DECL - || (TREE_PRIVATE (elt) || TREE_PROTECTED (elt)))) - { - /* We already complained about static data members in - finish_static_data_member_decl. */ - if (!VAR_P (elt)) - { - auto_diagnostic_group d; - if (permerror (DECL_SOURCE_LOCATION (elt), - TREE_CODE (TREE_TYPE (field)) == UNION_TYPE - ? "%q#D invalid; an anonymous union may " - "only have public non-static data members" - : "%q#D invalid; an anonymous struct may " - "only have public non-static data members", elt)) - { - static bool hint; - if (flag_permissive && !hint) - { - hint = true; - inform (DECL_SOURCE_LOCATION (elt), - "this flexibility is deprecated and will be " - "removed"); - } - } - } - } - TREE_PRIVATE (elt) = TREE_PRIVATE (field); TREE_PROTECTED (elt) = TREE_PROTECTED (field); @@ -3084,7 +3056,7 @@ finish_struct_anon_r (tree field, bool complain) int j=A().i; */ if (DECL_NAME (elt) == NULL_TREE && ANON_AGGR_TYPE_P (TREE_TYPE (elt))) - finish_struct_anon_r (elt, /*complain=*/false); + finish_struct_anon_r (elt); } } @@ -3103,7 +3075,7 @@ finish_struct_anon (tree t) if (DECL_NAME (field) == NULL_TREE && ANON_AGGR_TYPE_P (TREE_TYPE (field))) - finish_struct_anon_r (field, /*complain=*/true); + finish_struct_anon_r (field); } } diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 60dc2bf..e51c1b0 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5005,12 +5005,47 @@ fixup_anonymous_aggr (tree t) TYPE_HAS_COPY_ASSIGN (t) = 0; TYPE_HAS_CONST_COPY_ASSIGN (t) = 0; - /* Splice the implicitly generated functions out of TYPE_FIELDS. */ + /* Splice the implicitly generated functions out of TYPE_FIELDS and diagnose + invalid members. */ for (tree probe, *prev_p = &TYPE_FIELDS (t); (probe = *prev_p);) - if (TREE_CODE (probe) == FUNCTION_DECL && DECL_ARTIFICIAL (probe)) - *prev_p = DECL_CHAIN (probe); - else - prev_p = &DECL_CHAIN (probe); + { + if (TREE_CODE (probe) == FUNCTION_DECL && DECL_ARTIFICIAL (probe)) + *prev_p = DECL_CHAIN (probe); + else + prev_p = &DECL_CHAIN (probe); + + if (DECL_ARTIFICIAL (probe) + && (!DECL_IMPLICIT_TYPEDEF_P (probe) + || TYPE_ANON_P (TREE_TYPE (probe)))) + continue; + + if (TREE_CODE (probe) != FIELD_DECL + || (TREE_PRIVATE (probe) || TREE_PROTECTED (probe))) + { + /* We already complained about static data members in + finish_static_data_member_decl. */ + if (!VAR_P (probe)) + { + auto_diagnostic_group d; + if (permerror (DECL_SOURCE_LOCATION (probe), + TREE_CODE (t) == UNION_TYPE + ? "%q#D invalid; an anonymous union may " + "only have public non-static data members" + : "%q#D invalid; an anonymous struct may " + "only have public non-static data members", probe)) + { + static bool hint; + if (flag_permissive && !hint) + { + hint = true; + inform (DECL_SOURCE_LOCATION (probe), + "this flexibility is deprecated and will be " + "removed"); + } + } + } + } + } /* Splice all functions out of CLASSTYPE_MEMBER_VEC. */ vec* vec = CLASSTYPE_MEMBER_VEC (t); -- cgit v1.1 From a0fdff3cf33f72848d3f894272431a5d49fe6a16 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 5 Feb 2021 10:36:49 -0500 Subject: c++: Fix friend attributes [PR51344] 51344 was a problem with calling save_template_attributes twice for the same friend function: once from do_friend and once from grokmethod. The 2012 patch for the bug avoided creating an infinite loop when this happens, but it's better to avoid the duplication in the first place. This also restores the dependent attributes to the beginning of the attribute list, as originally intended. And then apply_late_template_attributes can avoid copying the non-dependent attributes. gcc/cp/ChangeLog: PR c++/51344 * decl2.c (grokfield): Call cplus_decl_attributes for friend. (save_template_attributes): Use chainon. * friend.c (do_friend): Remove attrlist parm. * cp-tree.h (do_friend): Adjust. * class.c (add_implicitly_declared_members): Adjust. * decl.c (grokdeclarator): Adjust. * pt.c (apply_late_template_attributes): Optimize. --- gcc/cp/class.c | 2 +- gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.c | 3 +-- gcc/cp/decl2.c | 10 +++++++--- gcc/cp/friend.c | 9 +-------- gcc/cp/pt.c | 51 +++++++++++++++++++++++---------------------------- 6 files changed, 34 insertions(+), 43 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index d693b43..dad3849 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3314,7 +3314,7 @@ add_implicitly_declared_members (tree t, tree* access_decls, bool is_friend = DECL_CONTEXT (space) != t; if (is_friend) do_friend (NULL_TREE, DECL_NAME (eq), eq, - NULL_TREE, NO_SPECIAL, true); + NO_SPECIAL, true); else { add_method (t, eq, false); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d3639e3..368d9f5 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6848,7 +6848,7 @@ extern void mark_exp_read (tree); extern int is_friend (tree, tree); extern void make_friend_class (tree, tree, bool); extern void add_friend (tree, tree, bool); -extern tree do_friend (tree, tree, tree, tree, +extern tree do_friend (tree, tree, tree, enum overload_flags, bool); extern void set_global_friend (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index e51c1b0..d1e7337 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13758,8 +13758,7 @@ grokdeclarator (const cp_declarator *declarator, } decl = do_friend (ctype, unqualified_id, decl, - *attrlist, flags, - funcdef_flag); + flags, funcdef_flag); return decl; } else diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index a82960f..89f874a 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -974,7 +974,11 @@ grokfield (const cp_declarator *declarator, if ((TREE_CODE (value) == FUNCTION_DECL || TREE_CODE (value) == TEMPLATE_DECL) && DECL_CONTEXT (value) != current_class_type) - return value; + { + if (attrlist) + cplus_decl_attributes (&value, attrlist, 0); + return value; + } /* Need to set this before push_template_decl. */ if (VAR_P (value)) @@ -1278,9 +1282,9 @@ save_template_attributes (tree *attr_p, tree *decl_p, int flags) tree old_attrs = *q; - /* Merge the late attributes at the beginning with the attribute + /* Place the late attributes at the beginning of the attribute list. */ - late_attrs = merge_attributes (late_attrs, *q); + late_attrs = chainon (late_attrs, *q); if (*q != late_attrs && !DECL_P (*decl_p) && !(flags & ATTR_FLAG_TYPE_IN_PLACE)) diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index ee73adb..4f62884 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -475,7 +475,7 @@ make_friend_class (tree type, tree friend_type, bool complain) tree do_friend (tree ctype, tree declarator, tree decl, - tree attrlist, enum overload_flags flags, + enum overload_flags flags, bool funcdef_flag) { gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); @@ -488,13 +488,6 @@ do_friend (tree ctype, tree declarator, tree decl, error ("friend declaration %qD may not have virt-specifiers", decl); - /* Unfortunately, we have to handle attributes here. Normally we would - handle them in start_decl_1, but since this is a friend decl start_decl_1 - never gets to see it. */ - - /* Set attributes here so if duplicate decl, will have proper attributes. */ - cplus_decl_attributes (&decl, attrlist, 0); - if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR) { declarator = TREE_OPERAND (declarator, 0); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index fc5065b..116bdd2 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11659,7 +11659,6 @@ static bool apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, tree args, tsubst_flags_t complain, tree in_decl) { - tree last_dep = NULL_TREE; tree t; tree *p; @@ -11685,39 +11684,35 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, p = &TREE_CHAIN (*p); } + /* save_template_attributes puts the dependent attributes at the beginning of + the list; find the non-dependent ones. */ for (t = attributes; t; t = TREE_CHAIN (t)) - if (ATTR_IS_DEPENDENT (t)) - { - last_dep = t; - attributes = copy_list (attributes); - break; - } + if (!ATTR_IS_DEPENDENT (t)) + break; + tree nondep = t; - *p = attributes; - if (last_dep) - { - tree late_attrs = NULL_TREE; - tree *q = &late_attrs; + /* Apply any non-dependent attributes. */ + *p = nondep; - for (; *p; ) + /* And then any dependent ones. */ + tree late_attrs = NULL_TREE; + tree *q = &late_attrs; + for (t = attributes; t != nondep; t = TREE_CHAIN (t)) + { + *q = tsubst_attribute (t, decl_p, args, complain, in_decl); + if (*q == error_mark_node) + return false; + if (*q == t) { - t = *p; - if (ATTR_IS_DEPENDENT (t)) - { - *q = tsubst_attribute (t, decl_p, args, complain, in_decl); - if (*q == error_mark_node) - return false; - *p = TREE_CHAIN (t); - TREE_CHAIN (t) = NULL_TREE; - while (*q) - q = &TREE_CHAIN (*q); - } - else - p = &TREE_CHAIN (t); + *q = copy_node (t); + TREE_CHAIN (*q) = NULL_TREE; } - - cplus_decl_attributes (decl_p, late_attrs, attr_flags); + while (*q) + q = &TREE_CHAIN (*q); } + + cplus_decl_attributes (decl_p, late_attrs, attr_flags); + return true; } -- cgit v1.1 From bc99c54de5a262ffc5f7801e16d919d335a53a8b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 25 Jan 2021 17:02:57 -0500 Subject: c++: Use empty field in constexpr eval. In discussion of PR98463, Jakub noted that cxx_fold_indirect_ref_1 was bailing out early for empty bases even when we do have fields for them (in C++17 mode or later). This corrects that. gcc/cp/ChangeLog: * constexpr.c (cxx_fold_indirect_ref_1): Only set *empty_base if we don't find a field. --- gcc/cp/constexpr.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index fa7eaed..9481a5b 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -4734,28 +4734,17 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, { tree optype = TREE_TYPE (op); unsigned HOST_WIDE_INT const_nunits; - if (off == 0) + if (off == 0 && similar_type_p (optype, type)) + return op; + else if (TREE_CODE (optype) == COMPLEX_TYPE + && similar_type_p (type, TREE_TYPE (optype))) { - if (similar_type_p (optype, type)) - return op; - /* Also handle conversion to an empty base class, which - is represented with a NOP_EXPR. */ /* *(foo *)&complexfoo => __real__ complexfoo */ - else if (TREE_CODE (optype) == COMPLEX_TYPE - && similar_type_p (type, TREE_TYPE (optype))) + if (off == 0) return build1_loc (loc, REALPART_EXPR, type, op); - } - /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ - else if (TREE_CODE (optype) == COMPLEX_TYPE - && similar_type_p (type, TREE_TYPE (optype)) - && tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off) - return build1_loc (loc, IMAGPART_EXPR, type, op); - if (is_empty_class (type) - && CLASS_TYPE_P (optype) - && DERIVED_FROM_P (type, optype)) - { - *empty_base = true; - return op; + /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ + else if (tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off) + return build1_loc (loc, IMAGPART_EXPR, type, op); } /* ((foo*)&vectorfoo)[x] => BIT_FIELD_REF */ else if (VECTOR_TYPE_P (optype) @@ -4834,6 +4823,15 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, return ret; } } + /* Also handle conversion to an empty base class, which + is represented with a NOP_EXPR. */ + if (is_empty_class (type) + && CLASS_TYPE_P (optype) + && DERIVED_FROM_P (type, optype)) + { + *empty_base = true; + return op; + } } return NULL_TREE; -- cgit v1.1 From 3c8e539dcfd955b24af44b95a1a900dc0a5dc4c9 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 30 Apr 2021 00:16:37 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a093657..86430fb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,56 @@ +2021-04-29 Jason Merrill + + * constexpr.c (cxx_fold_indirect_ref_1): Only set *empty_base if we + don't find a field. + +2021-04-29 Jason Merrill + + PR c++/51344 + * decl2.c (grokfield): Call cplus_decl_attributes for friend. + (save_template_attributes): Use chainon. + * friend.c (do_friend): Remove attrlist parm. + * cp-tree.h (do_friend): Adjust. + * class.c (add_implicitly_declared_members): Adjust. + * decl.c (grokdeclarator): Adjust. + * pt.c (apply_late_template_attributes): Optimize. + +2021-04-29 Jason Merrill + + PR c++/97974 + * class.c (finish_struct_anon_r): Drop complain parm. + Remove non-field diagnostic. + (finish_struct_anon): Adjust. + * decl.c (fixup_anonymous_aggr): Move non-field diagnostic here. + +2021-04-29 Jason Merrill + + * 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. + +2021-04-29 Jason Merrill + + * 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. + +2021-04-29 Patrick Palka + + PR c++/68942 + * pt.c (tsubst_copy_and_build) : When KOENIG_P, + set tf_conv during the initial substitution into the function. + +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. + 2021-04-28 Jakub Jelinek * module.cc: Remove #error that triggers if DEV-PHASE is empty. -- cgit v1.1 From 3307b9a07a3c515c6805d435e4bedada77687183 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 2 Mar 2021 16:30:41 -0500 Subject: c++: C++11 range-for and ovl/lkp_iterator We can't use C++11 range-based 'for' over a tree directly, because we don't know what kind of range we want to use it as. I suppose in some cases we could guess, but it seems better to tersely make it explicit. This patch adds range adaptors ovl_range and lkp_range for use as the range of a range-for, e.g. for (tree fn : lkp_range (fns)) { ... } This patch also removes the private copy ops from ovl_iterator; it's necessary for range-for, and these are effectively C++ forward_iterators, which allow copying, so I don't see a reason to prevent it. A bit more would need to be done to make them actually conform as C++11 forward iterators, but I don't think we particularly want to #include yet. gcc/cp/ChangeLog: * cp-tree.h (class ovl_iterator): Allow copying. Add op==. (class ovl_range, class lkp_range): New. * call.c (build_op_call_1, add_candidates): Use them. (build_op_delete_call, has_trivial_copy_assign_p): Likewise. (has_trivial_copy_p): Likewise. * class.c (handle_using_decl, get_basefndecls): Likewise. (maybe_warn_about_overly_private_class): Likewise. (warn_hidden, add_implicitly_declared_members): Likewise. (check_methods, clone_constructors_and_destructors): Likewise. (type_has_user_nondefault_constructor): Likewise. --- gcc/cp/call.c | 23 ++++++----------------- gcc/cp/class.c | 45 ++++++++++++++++++++------------------------- gcc/cp/cp-tree.h | 34 +++++++++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 47 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 678e120a..57bac05 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4914,10 +4914,8 @@ build_op_call_1 (tree obj, vec **args, tsubst_flags_t complain) || TYPE_REFFN_P (totype) || (TYPE_REF_P (totype) && TYPE_PTRFN_P (TREE_TYPE (totype)))) - for (ovl_iterator iter (TREE_VALUE (convs)); iter; ++iter) + for (tree fn : ovl_range (TREE_VALUE (convs))) { - tree fn = *iter; - if (DECL_NONCONVERTING_P (fn)) continue; @@ -5981,10 +5979,8 @@ add_candidates (tree fns, tree first_arg, const vec *args, which = non_templates; again: - for (lkp_iterator iter (fns); iter; ++iter) + for (tree fn : lkp_range (fns)) { - fn = *iter; - if (check_converting && DECL_NONCONVERTING_P (fn)) continue; if (check_list_ctor && !is_list_ctor (fn)) @@ -7016,10 +7012,8 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, the usual deallocation function, so we shouldn't complain about using the operator delete (void *, size_t). */ if (DECL_CLASS_SCOPE_P (fn)) - for (lkp_iterator iter (MAYBE_BASELINK_FUNCTIONS (fns)); - iter; ++iter) + for (tree elt : lkp_range (MAYBE_BASELINK_FUNCTIONS (fns))) { - tree elt = *iter; if (usual_deallocation_fn_p (elt) && FUNCTION_ARG_CHAIN (elt) == void_list_node) goto ok; @@ -7062,9 +7056,8 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, allocation function. If the lookup finds a single matching deallocation function, that function will be called; otherwise, no deallocation function will be called." */ - for (lkp_iterator iter (MAYBE_BASELINK_FUNCTIONS (fns)); iter; ++iter) + for (tree elt : lkp_range (MAYBE_BASELINK_FUNCTIONS (fns))) { - tree elt = *iter; dealloc_info di_elt; if (usual_deallocation_fn_p (elt, &di_elt)) { @@ -9669,10 +9662,8 @@ has_trivial_copy_assign_p (tree type, bool access, bool *hasassign) /* Iterate over overloads of the assignment operator, checking accessible copy assignments for triviality. */ - for (ovl_iterator oi (fns); oi; ++oi) + for (tree f : ovl_range (fns)) { - tree f = *oi; - /* Skip operators that aren't copy assignments. */ if (!copy_fn_p (f)) continue; @@ -9715,10 +9706,8 @@ has_trivial_copy_p (tree type, bool access, bool hasctor[2]) tree fns = get_class_binding (type, complete_ctor_identifier); bool all_trivial = true; - for (ovl_iterator oi (fns); oi; ++oi) + for (tree f : ovl_range (fns)) { - tree f = *oi; - /* Skip template constructors. */ if (TREE_CODE (f) != FUNCTION_DECL) continue; diff --git a/gcc/cp/class.c b/gcc/cp/class.c index dad3849..66bc1ee 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1347,10 +1347,10 @@ handle_using_decl (tree using_decl, tree t) /* Make type T see field decl FDECL with access ACCESS. */ if (flist) - for (ovl_iterator iter (flist); iter; ++iter) + for (tree f : ovl_range (flist)) { - add_method (t, *iter, true); - alter_access (t, *iter, access); + add_method (t, f, true); + alter_access (t, f, access); } else if (USING_DECL_UNRELATED_P (using_decl)) { @@ -2259,18 +2259,20 @@ maybe_warn_about_overly_private_class (tree t) if (!TYPE_HAS_COPY_CTOR (t)) nonprivate_ctor = true; else - for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); - !nonprivate_ctor && iter; ++iter) - if (TREE_PRIVATE (*iter)) + for (tree fn : ovl_range (CLASSTYPE_CONSTRUCTORS (t))) + if (TREE_PRIVATE (fn)) continue; - else if (copy_fn_p (*iter) || move_fn_p (*iter)) + else if (copy_fn_p (fn) || move_fn_p (fn)) /* Ideally, we wouldn't count any constructor that takes an argument of the class type as a parameter, because such things cannot be used to construct an instance of the class unless you already have one. */ - copy_or_move = *iter; + copy_or_move = fn; else - nonprivate_ctor = true; + { + nonprivate_ctor = true; + break; + } if (!nonprivate_ctor) { @@ -2876,10 +2878,8 @@ get_basefndecls (tree name, tree t, vec *base_fndecls) bool found_decls = false; /* Find virtual functions in T with the indicated NAME. */ - for (ovl_iterator iter (get_class_binding (t, name)); iter; ++iter) + for (tree method : ovl_range (get_class_binding (t, name))) { - tree method = *iter; - if (TREE_CODE (method) == FUNCTION_DECL && DECL_VINDEX (method)) { base_fndecls->safe_push (method); @@ -2988,9 +2988,8 @@ warn_hidden (tree t) continue; /* Remove any overridden functions. */ - for (ovl_iterator iter (fns); iter; ++iter) + for (tree fndecl : ovl_range (fns)) { - tree fndecl = *iter; if (TREE_CODE (fndecl) == FUNCTION_DECL && DECL_VINDEX (fndecl)) { @@ -3334,8 +3333,8 @@ add_implicitly_declared_members (tree t, tree* access_decls, tree ctor_list = decl; location_t loc = input_location; input_location = DECL_SOURCE_LOCATION (using_decl); - for (ovl_iterator iter (ctor_list); iter; ++iter) - one_inherited_ctor (*iter, t, using_decl); + for (tree fn : ovl_range (ctor_list)) + one_inherited_ctor (fn, t, using_decl); *access_decls = TREE_CHAIN (*access_decls); input_location = loc; } @@ -4751,9 +4750,8 @@ check_methods (tree t) TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = true; } - for (ovl_iterator i (CLASSTYPE_CONSTRUCTORS (t)); i; ++i) + for (tree fn : ovl_range (CLASSTYPE_CONSTRUCTORS (t))) { - tree fn = *i; if (!user_provided_p (fn)) /* Might be trivial. */; else if (copy_fn_p (fn)) @@ -4762,10 +4760,8 @@ check_methods (tree t) TYPE_HAS_COMPLEX_MOVE_CTOR (t) = true; } - for (ovl_iterator i (get_class_binding_direct (t, assign_op_identifier)); - i; ++i) + for (tree fn : ovl_range (get_class_binding_direct (t, assign_op_identifier))) { - tree fn = *i; if (!user_provided_p (fn)) /* Might be trivial. */; else if (copy_fn_p (fn)) @@ -5107,8 +5103,8 @@ clone_constructors_and_destructors (tree t) { /* We do not need to propagate the usingness to the clone, at this point that is not needed. */ - for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter) - clone_cdtor (*iter, /*update_methods=*/true); + for (tree fn : ovl_range (CLASSTYPE_CONSTRUCTORS (t))) + clone_cdtor (fn, /*update_methods=*/true); if (tree dtor = CLASSTYPE_DESTRUCTOR (t)) clone_cdtor (dtor, /*update_methods=*/true); @@ -5283,9 +5279,8 @@ type_has_user_nondefault_constructor (tree t) if (!TYPE_HAS_USER_CONSTRUCTOR (t)) return false; - for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter) + for (tree fn : ovl_range (CLASSTYPE_CONSTRUCTORS (t))) { - tree fn = *iter; if (user_provided_p (fn) && (TREE_CODE (fn) == TEMPLATE_DECL || (skip_artificial_parms_for (fn, DECL_ARGUMENTS (fn)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 368d9f5..a08867a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -817,11 +817,6 @@ class ovl_iterator { { } - private: - /* Do not duplicate. */ - ovl_iterator &operator= (const ovl_iterator &); - ovl_iterator (const ovl_iterator &); - public: operator bool () const { @@ -841,6 +836,10 @@ class ovl_iterator { return fn; } + bool operator== (const ovl_iterator &o) const + { + return ovl == o.ovl; + } tree get_using () const { gcc_checking_assert (using_p ()); @@ -903,6 +902,19 @@ class ovl_iterator { static tree reveal_node (tree ovl, tree node); }; +/* Treat a tree as a range of ovl_iterator, e.g. + for (tree f : ovl_range (fns)) { ... } */ + +class ovl_range +{ + tree t; + bool allow; +public: + explicit ovl_range (tree t, bool allow = false): t(t), allow(allow) { } + ovl_iterator begin() { return ovl_iterator (t, allow); } + ovl_iterator end() { return ovl_iterator (NULL_TREE, allow); } +}; + /* Iterator over a (potentially) 2 dimensional overload, which is produced by name lookup. */ @@ -935,6 +947,18 @@ class lkp_iterator : public ovl_iterator { } }; +/* Treat a tree as a range of lkp_iterator, e.g. + for (tree f : lkp_range (fns)) { ... } */ + +class lkp_range +{ + tree t; +public: + lkp_range (tree t): t(t) { } + lkp_iterator begin() { return lkp_iterator (t); } + lkp_iterator end() { return lkp_iterator (NULL_TREE); } +}; + /* hash traits for declarations. Hashes potential overload sets via DECL_NAME. */ -- cgit v1.1 From 620a06358e45f86bb0121b53cb1997824f2d7e7e Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 2 May 2021 00:16:20 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 86430fb..fe1ed7e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2021-05-01 Jason Merrill + + * cp-tree.h (class ovl_iterator): Allow copying. Add op==. + (class ovl_range, class lkp_range): New. + * call.c (build_op_call_1, add_candidates): Use them. + (build_op_delete_call, has_trivial_copy_assign_p): Likewise. + (has_trivial_copy_p): Likewise. + * class.c (handle_using_decl, get_basefndecls): Likewise. + (maybe_warn_about_overly_private_class): Likewise. + (warn_hidden, add_implicitly_declared_members): Likewise. + (check_methods, clone_constructors_and_destructors): Likewise. + (type_has_user_nondefault_constructor): Likewise. + 2021-04-29 Jason Merrill * constexpr.c (cxx_fold_indirect_ref_1): Only set *empty_base if we -- cgit v1.1 From 6252e35cf5cea9a30a57ceffbc7a9f3160900a45 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 28 Apr 2021 19:11:14 -0400 Subject: c++: Remove GCC12 FIXME for DR1312 This patch removes a FIXME I left for myself for GCC 12, along with adjusting the relevant test. gcc/cp/ChangeLog: DR 1312 * constexpr.c (cxx_eval_constant_expression): Don't check integer_zerop. gcc/testsuite/ChangeLog: DR 1312 * g++.dg/cpp0x/constexpr-cast2.C: Remove XFAILs. --- gcc/cp/constexpr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 9481a5b..9cb761d 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -6745,8 +6745,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, /* [expr.const]: a conversion from type cv void* to a pointer-to-object type cannot be part of a core constant expression as a resolution to DR 1312. */ - if (integer_zerop (op) /* FIXME: Remove in GCC 12. */ - && TYPE_PTROB_P (type) + if (TYPE_PTROB_P (type) && TYPE_PTR_P (TREE_TYPE (op)) && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (op))) /* Inside a call to std::construct_at or to -- cgit v1.1 From c9b6890d0b6aa030b307fdb620f8c53ed59ca3b5 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 22 Apr 2021 17:32:01 -0400 Subject: c++: Fix ICE with invalid requires-expression [PR100055] This fixes a crash on invalid requires-expression: in this test, current_template_parms is null so accessing TEMPLATE_PARMS_CONSTRAINTS is going to fail. So don't crash, but make sure we've complained already. gcc/cp/ChangeLog: PR c++/100055 * decl.c (grokfndecl): Check current_template_parms. gcc/testsuite/ChangeLog: PR c++/100055 * g++.dg/concepts/diagnostic18.C: New test. --- gcc/cp/decl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index d1e7337..316ad4c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -9737,7 +9737,14 @@ grokfndecl (tree ctype, && (processing_template_decl > template_class_depth (ctx))); if (memtmpl) - tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); + { + if (!current_template_parms) + /* If there are no template parameters, something must have + gone wrong. */ + gcc_assert (seen_error ()); + else + tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); + } tree ci = build_constraints (tmpl_reqs, decl_reqs); if (concept_p && ci) { -- cgit v1.1 From eef4fa6968ae0682679c27dae06409db3d113d5d Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 3 May 2021 13:35:26 -0400 Subject: c++: mark_used and ADL with template-id [PR100344] My r11-295 patch for PR68942 didn't consider that the callee of an ADL-eligible function call can be a TEMPLATE_ID_EXPR, and we don't want to disable mark_used when substituting into the template arguments of this TEMPLATE_ID_EXPR because the arguments are clearly used regardless of the outcome of ADL. In the first testcase below, this oversight causes us to trip over the assert in build_call_a for the call to find_index because the function no longer had its TREE_USED bit set from mark_used. So this patch restricts the original fix to disable mark_used only when the callee is a FUNCTION_DECL, which seems to be the only case that matters for PR68942. For instance, in the second testcase below we already don't mark_used the deleted function specialization even before r11-295. gcc/cp/ChangeLog: PR c++/68942 PR c++/100344 * pt.c (tsubst_copy_and_build) : Set tf_conv only when the callee is a FUNCTION_DECL. gcc/testsuite/ChangeLog: PR c++/68942 PR c++/100344 * g++.dg/template/call8.C: New test. * g++.dg/template/koenig12a.C: New test. --- gcc/cp/pt.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 116bdd2..36a8cb5 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20227,11 +20227,13 @@ tsubst_copy_and_build (tree t, /* Avoid error about taking the address of a constructor. */ function = TREE_OPERAND (function, 0); - /* When KOENIG_P, we don't want to mark_used the callee before - augmenting the overload set via ADL, so during this initial - substitution we disable mark_used by setting tf_conv (68942). */ - function = tsubst_copy_and_build (function, args, - complain | (koenig_p * tf_conv), + tsubst_flags_t subcomplain = complain; + if (koenig_p && TREE_CODE (function) == FUNCTION_DECL) + /* When KOENIG_P, we don't want to mark_used the callee before + augmenting the overload set via ADL, so during this initial + substitution we disable mark_used by setting tf_conv (68942). */ + subcomplain |= tf_conv; + function = tsubst_copy_and_build (function, args, subcomplain, in_decl, !qualified_p, integral_constant_expression_p); -- cgit v1.1 From 2a6fc19e655e696bf0df9b7aaedf9848b23f07f3 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 3 May 2021 13:35:37 -0400 Subject: c++: base-clause parsing and implicit 'this' [PR100362] My r11-6815 change to defer access checking when processing a base-clause removed a pair of pushclass / popclass calls that seemed to be unnecessary now that we'd also defer access checking while parsing the base-clause. But it turns out these calls make a difference in the below testcase, where we have a local class whose base-clause implicitly uses the 'this' of the enclosing class. Before r11-6815, while parsing the base-clause of the local class, maybe_resolve_dummy would fail to resolve the dummy 'this' object because the current scope would be the local class. Now, since the current scope is the lambda, maybe_resolve_dummy succeeds and returns the 'this' for the enclosing class Qux. Later, during deferred instantiation of the local class, we get confused trying to resolve the access of 'a_' through this non-dummy 'this'. So this patch just reinstates the calls to pushclass / popclass that were removed in r11-6815. gcc/cp/ChangeLog: PR c++/100362 * parser.c (cp_parser_class_head): Reinstate calls to pushclass and popclass when parsing the base-clause that were removed in r11-6815. gcc/testsuite/ChangeLog: PR c++/100362 * g++.dg/cpp1y/lambda-generic-100362.C: New test. --- gcc/cp/parser.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 9603a1e..58bd6d1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -25690,7 +25690,13 @@ cp_parser_class_head (cp_parser* parser, until the entire list has been seen, as per [class.access.general]. */ push_deferring_access_checks (dk_deferred); if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) - bases = cp_parser_base_clause (parser); + { + if (type) + pushclass (type); + bases = cp_parser_base_clause (parser); + if (type) + popclass (); + } else bases = NULL_TREE; -- cgit v1.1 From e690396da796cc4e1a0592336b37fec4e97262da Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 4 May 2021 00:16:53 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fe1ed7e..7ad197e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,28 @@ +2021-05-03 Patrick Palka + + PR c++/100362 + * parser.c (cp_parser_class_head): Reinstate calls to pushclass + and popclass when parsing the base-clause that were removed in + r11-6815. + +2021-05-03 Patrick Palka + + PR c++/68942 + PR c++/100344 + * pt.c (tsubst_copy_and_build) : Set tf_conv + only when the callee is a FUNCTION_DECL. + +2021-05-03 Marek Polacek + + PR c++/100055 + * decl.c (grokfndecl): Check current_template_parms. + +2021-05-03 Marek Polacek + + DR 1312 + * constexpr.c (cxx_eval_constant_expression): Don't check + integer_zerop. + 2021-05-01 Jason Merrill * cp-tree.h (class ovl_iterator): Allow copying. Add op==. -- 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') 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 99e8df7a4cc0bb1bfa49e69ccb0f7e02c9755e3c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 5 May 2021 00:16:54 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7ad197e..fcb2075 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2021-05-04 Tobias Burnus + + * semantics.c (finish_omp_reduction_clause): Accept float + complex + for || and && reductions. + 2021-05-03 Patrick Palka PR c++/100362 -- cgit v1.1 From 14ed21f8749ae359690d9c4a69ca38cc45d0d1b0 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 4 May 2021 21:33:36 -0400 Subject: c++: don't call 'rvalue' in coroutines code A change to check glvalue_p rather than specifically for TARGET_EXPR revealed issues with the coroutines code's use of the 'rvalue' function, which shouldn't be used on class glvalues, so I've removed those calls. In build_co_await I just dropped them, because I don't see anything in the co_await specification that indicates that we would want to move from an lvalue result of operator co_await. And simplified that code while I was touching it; cp_build_modify_expr (...INIT_EXPR...) will call the constructor. In morph_fn_to_coro I changed the handling of the rvalue reference coroutine frame field to use move, to treat the rval ref as an xvalue. I used forward_parm to pass the function parms to the constructor for the field. And I simplified the return handling so we get the desired rvalue semantics from the normal implicit move on return. I question default-initializing the non-void return value of the function if get_return_object returns void; I'm not messing with it here, but I've filed PR100476 about it. gcc/cp/ChangeLog: * coroutines.cc (build_co_await): Don't call 'rvalue'. (flatten_await_stmt): Simplify initialization. (morph_fn_to_coro): Change 'rvalue' to 'move'. Simplify. gcc/testsuite/ChangeLog: * g++.dg/coroutines/coro-bad-gro-00-class-gro-scalar-return.C: Adjust diagnostic. --- gcc/cp/coroutines.cc | 117 +++++++++++++-------------------------------------- 1 file changed, 30 insertions(+), 87 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index dbd703a..7166206 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -950,18 +950,11 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind) e_proxy = o; o = NULL_TREE; /* The var is already present. */ } - else if (type_build_ctor_call (o_type)) - { - e_proxy = get_awaitable_var (suspend_kind, o_type); - releasing_vec arg (make_tree_vector_single (rvalue (o))); - o = build_special_member_call (e_proxy, complete_ctor_identifier, - &arg, o_type, LOOKUP_NORMAL, - tf_warning_or_error); - } else { e_proxy = get_awaitable_var (suspend_kind, o_type); - o = build2 (INIT_EXPR, o_type, e_proxy, rvalue (o)); + o = cp_build_modify_expr (loc, e_proxy, INIT_EXPR, o, + tf_warning_or_error); } /* I suppose we could check that this is contextually convertible to bool. */ @@ -2989,15 +2982,8 @@ flatten_await_stmt (var_nest_node *n, hash_set *promoted, gcc_checking_assert (!already_present); tree inner = TREE_OPERAND (init, 1); gcc_checking_assert (TREE_CODE (inner) != COND_EXPR); - if (type_build_ctor_call (var_type)) - { - releasing_vec p_in (make_tree_vector_single (init)); - init = build_special_member_call (var, complete_ctor_identifier, - &p_in, var_type, LOOKUP_NORMAL, - tf_warning_or_error); - } - else - init = build2 (INIT_EXPR, var_type, var, init); + init = cp_build_modify_expr (input_location, var, INIT_EXPR, init, + tf_warning_or_error); /* Simplify for the case that we have an init containing the temp alone. */ if (t == n->init && n->var == NULL_TREE) @@ -4862,43 +4848,19 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) vec_safe_push (promise_args, this_ref); } else if (parm.rv_ref) - vec_safe_push (promise_args, rvalue(fld_idx)); + vec_safe_push (promise_args, move (fld_idx)); else vec_safe_push (promise_args, fld_idx); if (parm.rv_ref || parm.pt_ref) /* Initialise the frame reference field directly. */ - r = build_modify_expr (fn_start, TREE_OPERAND (fld_idx, 0), - parm.frame_type, INIT_EXPR, - DECL_SOURCE_LOCATION (arg), arg, - DECL_ARG_TYPE (arg)); - else if (type_build_ctor_call (parm.frame_type)) - { - vec *p_in; - if (CLASS_TYPE_P (parm.frame_type) - && classtype_has_non_deleted_move_ctor (parm.frame_type)) - p_in = make_tree_vector_single (move (arg)); - else if (lvalue_p (arg)) - p_in = make_tree_vector_single (rvalue (arg)); - else - p_in = make_tree_vector_single (arg); - /* Construct in place or move as relevant. */ - r = build_special_member_call (fld_idx, complete_ctor_identifier, - &p_in, parm.frame_type, - LOOKUP_NORMAL, - tf_warning_or_error); - release_tree_vector (p_in); - } + r = cp_build_modify_expr (fn_start, TREE_OPERAND (fld_idx, 0), + INIT_EXPR, arg, tf_warning_or_error); else { - if (!same_type_p (parm.frame_type, DECL_ARG_TYPE (arg))) - r = build1_loc (DECL_SOURCE_LOCATION (arg), CONVERT_EXPR, - parm.frame_type, arg); - else - r = arg; - r = build_modify_expr (fn_start, fld_idx, parm.frame_type, - INIT_EXPR, DECL_SOURCE_LOCATION (arg), r, - TREE_TYPE (r)); + r = forward_parm (arg); + r = cp_build_modify_expr (fn_start, fld_idx, INIT_EXPR, r, + tf_warning_or_error); } finish_expr_stmt (r); if (!parm.trivial_dtor) @@ -5044,16 +5006,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) DECL_IGNORED_P (gro) = true; add_decl_expr (gro); gro_bind_vars = gro; - if (type_build_ctor_call (gro_type)) - { - vec *arg = make_tree_vector_single (get_ro); - r = build_special_member_call (gro, complete_ctor_identifier, - &arg, gro_type, LOOKUP_NORMAL, - tf_warning_or_error); - release_tree_vector (arg); - } - else - r = build2_loc (fn_start, INIT_EXPR, gro_type, gro, get_ro); + r = cp_build_modify_expr (input_location, gro, INIT_EXPR, get_ro, + tf_warning_or_error); /* The constructed object might require a cleanup. */ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (gro_type)) { @@ -5111,37 +5065,26 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) if (same_type_p (gro_type, fn_return_type)) r = gro_is_void_p ? NULL_TREE : DECL_RESULT (orig); + else if (!gro_is_void_p) + /* check_return_expr will automatically return gro as an rvalue via + treat_lvalue_as_rvalue_p. */ + r = gro; + else if (CLASS_TYPE_P (fn_return_type)) + { + /* For class type return objects, we can attempt to construct, + even if the gro is void. ??? Citation ??? c++/100476 */ + r = build_special_member_call (NULL_TREE, + complete_ctor_identifier, NULL, + fn_return_type, LOOKUP_NORMAL, + tf_warning_or_error); + r = build_cplus_new (fn_return_type, r, tf_warning_or_error); + } else { - if (CLASS_TYPE_P (fn_return_type)) - { - /* For class type return objects, we can attempt to construct, - even if the gro is void. */ - vec *args = NULL; - vec **arglist = NULL; - if (!gro_is_void_p) - { - args = make_tree_vector_single (rvalue (gro)); - arglist = &args; - } - r = build_special_member_call (NULL_TREE, - complete_ctor_identifier, arglist, - fn_return_type, LOOKUP_NORMAL, - tf_warning_or_error); - r = build_cplus_new (fn_return_type, r, tf_warning_or_error); - if (args) - release_tree_vector (args); - } - else if (gro_is_void_p) - { - /* We can't initialize a non-class return value from void. */ - error_at (input_location, "cannot initialize a return object of type" - " %qT with an rvalue of type %", fn_return_type); - r = error_mark_node; - } - else - r = build1_loc (input_location, CONVERT_EXPR, - fn_return_type, rvalue (gro)); + /* We can't initialize a non-class return value from void. */ + error_at (input_location, "cannot initialize a return object of type" + " %qT with an rvalue of type %", fn_return_type); + r = error_mark_node; } finish_return_stmt (r); -- cgit v1.1 From fc178519771db508c03611cff4a1466cf67fce1d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 5 May 2021 22:25:45 -0400 Subject: c++: avoid non-TARGET_EXPR class prvalues Around PR98469 I asked Jakub to wrap a class BIT_CAST_EXPR in TARGET_EXPR; SPACESHIP_EXPR needs the same thing. The dummy CAST_EXPR created in can_convert is another instance of a non-TARGET_EXPR prvalue, so let's use the declval-like build_stub_object there instead. gcc/cp/ChangeLog: * cp-tree.h (build_stub_object): Declare. * method.c (build_stub_object): No longer static. * call.c (can_convert): Use it. * tree.c (build_dummy_object): Adjust comment. * typeck.c (cp_build_binary_op): Wrap SPACESHIP_EXPR in a TARGET_EXPR. --- gcc/cp/call.c | 2 +- gcc/cp/cp-tree.h | 1 + gcc/cp/method.c | 2 +- gcc/cp/tree.c | 3 ++- gcc/cp/typeck.c | 2 ++ 5 files changed, 7 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 57bac05..d985e4e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -12177,7 +12177,7 @@ can_convert (tree to, tree from, tsubst_flags_t complain) /* implicit_conversion only considers user-defined conversions if it has an expression for the call argument list. */ if (CLASS_TYPE_P (from) || CLASS_TYPE_P (to)) - arg = build1 (CAST_EXPR, from, NULL_TREE); + arg = build_stub_object (from); return can_convert_arg (to, from, arg, LOOKUP_IMPLICIT, complain); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a08867a..122dadf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6968,6 +6968,7 @@ extern tree get_copy_ctor (tree, tsubst_flags_t); extern tree get_copy_assign (tree); extern tree get_default_ctor (tree); extern tree get_dtor (tree, tsubst_flags_t); +extern tree build_stub_object (tree); extern tree strip_inheriting_ctors (tree); extern tree inherited_ctor_binfo (tree); extern bool base_ctor_omit_inherited_parms (tree); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 0f416be..f8c9456 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1793,7 +1793,7 @@ build_stub_type (tree type, int quals, bool rvalue) /* Build a dummy glvalue from dereferencing a dummy reference of type REFTYPE. */ -static tree +tree build_stub_object (tree reftype) { if (!TYPE_REF_P (reftype)) diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 3a20cd3..4ccd7a3 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -4175,7 +4175,8 @@ member_p (const_tree decl) } /* Create a placeholder for member access where we don't actually have an - object that the access is against. */ + object that the access is against. For a general declval equivalent, + use build_stub_object instead. */ tree build_dummy_object (tree type) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 50d0f1e..5af47ce 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5931,6 +5931,8 @@ cp_build_binary_op (const op_location_t &location, if (!processing_template_decl) { + if (resultcode == SPACESHIP_EXPR) + result = get_target_expr_sfinae (result, complain); op0 = cp_fully_fold (op0); /* Only consider the second argument if the first isn't overflowed. */ if (!CONSTANT_CLASS_P (op0) || TREE_OVERFLOW_P (op0)) -- cgit v1.1 From 7a5dd3ed49d1b328865520ee30e758158516ca2b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 4 May 2021 21:33:33 -0400 Subject: c++: reject class lvalues in 'rvalue' Wrapping a class lvalue in NON_LVALUE_EXPR is not sufficient to make it a usable prvalue; callers must use force_rvalue instead. gcc/cp/ChangeLog: * tree.c (rvalue): Assert expr is not a class lvalue. --- gcc/cp/tree.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 4ccd7a3..7f148b4 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -940,7 +940,12 @@ rvalue (tree expr) /* We need to do this for rvalue refs as well to get the right answer from decltype; see c++/36628. */ if (!processing_template_decl && glvalue_p (expr)) - expr = build1 (NON_LVALUE_EXPR, type, expr); + { + /* But don't use this function for class lvalues; use move (to treat an + lvalue as an xvalue) or force_rvalue (to make a prvalue copy). */ + gcc_checking_assert (!CLASS_TYPE_P (type)); + expr = build1 (NON_LVALUE_EXPR, type, expr); + } else if (type != TREE_TYPE (expr)) expr = build_nop (type, expr); -- cgit v1.1 From 62d87a321b29f9febdacc6220367021d98db3057 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 8 May 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fcb2075..8bbc030 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,22 @@ +2021-05-07 Jason Merrill + + * tree.c (rvalue): Assert expr is not a class lvalue. + +2021-05-07 Jason Merrill + + * cp-tree.h (build_stub_object): Declare. + * method.c (build_stub_object): No longer static. + * call.c (can_convert): Use it. + * tree.c (build_dummy_object): Adjust comment. + * typeck.c (cp_build_binary_op): Wrap SPACESHIP_EXPR in a + TARGET_EXPR. + +2021-05-07 Jason Merrill + + * coroutines.cc (build_co_await): Don't call 'rvalue'. + (flatten_await_stmt): Simplify initialization. + (morph_fn_to_coro): Change 'rvalue' to 'move'. Simplify. + 2021-05-04 Tobias Burnus * semantics.c (finish_omp_reduction_clause): Accept float + complex -- cgit v1.1 From ec728fb0026bbe5bc9f0d9ccb4215000f77ab206 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Tue, 16 Mar 2021 13:22:55 +0100 Subject: c++: remove redundand NULL check. gcc/cp/ChangeLog: PR c++/99616 * decl.c (grokdeclarator): Remove redundant NULL check. --- gcc/cp/decl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 316ad4c..8bf524b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -12310,7 +12310,7 @@ grokdeclarator (const cp_declarator *declarator, int attr_flags; attr_flags = 0; - if (declarator == NULL || declarator->kind == cdk_id) + if (declarator->kind == cdk_id) attr_flags |= (int) ATTR_FLAG_DECL_NEXT; if (declarator->kind == cdk_function) attr_flags |= (int) ATTR_FLAG_FUNCTION_NEXT; -- cgit v1.1 From 6ba3079dce89d9b63bf5dbd5e320ea2bf96f196b Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 17 Mar 2021 16:36:44 +0100 Subject: Come up with startswith function. gcc/ada/ChangeLog: * gcc-interface/utils.c (def_builtin_1): Use startswith function instead of strncmp. gcc/analyzer/ChangeLog: * sm-file.cc (is_file_using_fn_p): Use startswith function instead of strncmp. gcc/ChangeLog: * builtins.c (is_builtin_name): Use startswith function instead of strncmp. * collect2.c (main): Likewise. (has_lto_section): Likewise. (scan_libraries): Likewise. * coverage.c (coverage_checksum_string): Likewise. (coverage_init): Likewise. * dwarf2out.c (is_cxx): Likewise. (gen_compile_unit_die): Likewise. * gcc-ar.c (main): Likewise. * gcc.c (init_spec): Likewise. (read_specs): Likewise. (execute): Likewise. (check_live_switch): Likewise. * genattrtab.c (write_attr_case): Likewise. (IS_ATTR_GROUP): Likewise. * gencfn-macros.c (main): Likewise. * gengtype.c (type_for_name): Likewise. (gen_rtx_next): Likewise. (get_file_langdir): Likewise. (write_local): Likewise. * genmatch.c (get_operator): Likewise. (get_operand_type): Likewise. (expr::gen_transform): Likewise. * genoutput.c (validate_optab_operands): Likewise. * incpath.c (add_sysroot_to_chain): Likewise. * langhooks.c (lang_GNU_C): Likewise. (lang_GNU_CXX): Likewise. (lang_GNU_Fortran): Likewise. (lang_GNU_OBJC): Likewise. * lto-wrapper.c (run_gcc): Likewise. * omp-general.c (omp_max_simt_vf): Likewise. * omp-low.c (omp_runtime_api_call): Likewise. * opts-common.c (parse_options_from_collect_gcc_options): Likewise. * read-rtl-function.c (function_reader::read_rtx_operand_r): Likewise. * real.c (real_from_string): Likewise. * selftest.c (assert_str_startswith): Likewise. * timevar.c (timer::validate_phases): Likewise. * tree.c (get_file_function_name): Likewise. * ubsan.c (ubsan_use_new_style_p): Likewise. * varasm.c (default_function_rodata_section): Likewise. (incorporeal_function_p): Likewise. (default_section_type_flags): Likewise. * system.h (startswith): Define startswith. gcc/c-family/ChangeLog: * c-ada-spec.c (print_destructor): Use startswith function instead of strncmp. (dump_ada_declaration): Likewise. * c-common.c (disable_builtin_function): Likewise. (def_builtin_1): Likewise. * c-format.c (check_tokens): Likewise. (check_plain): Likewise. (convert_format_name_to_system_name): Likewise. gcc/c/ChangeLog: * c-aux-info.c (affix_data_type): Use startswith function instead of strncmp. * c-typeck.c (build_function_call_vec): Likewise. * gimple-parser.c (c_parser_gimple_parse_bb_spec): Likewise. gcc/cp/ChangeLog: * decl.c (duplicate_decls): Use startswith function instead of strncmp. (cxx_builtin_function): Likewise. (omp_declare_variant_finalize_one): Likewise. (grokfndecl): Likewise. * error.c (dump_decl_name): Likewise. * mangle.c (find_decomp_unqualified_name): Likewise. (write_guarded_var_name): Likewise. (decl_tls_wrapper_p): Likewise. * parser.c (cp_parser_simple_type_specifier): Likewise. (cp_parser_tx_qualifier_opt): Likewise. * pt.c (template_parm_object_p): Likewise. (dguide_name_p): Likewise. gcc/d/ChangeLog: * d-builtins.cc (do_build_builtin_fn): Use startswith function instead of strncmp. * dmd/dinterpret.c (evaluateIfBuiltin): Likewise. * dmd/dmangle.c: Likewise. * dmd/hdrgen.c: Likewise. * dmd/identifier.c (Identifier::toHChars2): Likewise. gcc/fortran/ChangeLog: * decl.c (variable_decl): Use startswith function instead of strncmp. (gfc_match_end): Likewise. * gfortran.h (gfc_str_startswith): Likewise. * module.c (load_omp_udrs): Likewise. (read_module): Likewise. * options.c (gfc_handle_runtime_check_option): Likewise. * primary.c (match_arg_list_function): Likewise. * trans-decl.c (gfc_get_symbol_decl): Likewise. * trans-expr.c (gfc_conv_procedure_call): Likewise. * trans-intrinsic.c (gfc_conv_ieee_arithmetic_function): Likewise. gcc/go/ChangeLog: * gofrontend/runtime.cc (Runtime::name_to_code): Use startswith function instead of strncmp. gcc/objc/ChangeLog: * objc-act.c (objc_string_ref_type_p): Use startswith function instead of strncmp. * objc-encoding.c (encode_type): Likewise. * objc-next-runtime-abi-02.c (has_load_impl): Likewise. --- gcc/cp/decl.c | 15 +++++++-------- gcc/cp/error.c | 2 +- gcc/cp/mangle.c | 11 +++++------ gcc/cp/parser.c | 7 +++---- gcc/cp/pt.c | 5 ++--- 5 files changed, 18 insertions(+), 22 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 8bf524b..bc3928d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1609,8 +1609,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (name[0] == '_' && name[1] == '_' - && (strncmp (name + 2, "builtin_", - strlen ("builtin_")) == 0 + && (startswith (name + 2, "builtin_") || (len = strlen (name)) <= strlen ("___chk") || memcmp (name + len - strlen ("_chk"), "_chk", strlen ("_chk") + 1) != 0)) @@ -4828,7 +4827,7 @@ cxx_builtin_function (tree decl) /* In the user's namespace, it must be declared before use. */ hiding = true; else if (IDENTIFIER_LENGTH (id) > strlen ("___chk") - && 0 != strncmp (name + 2, "builtin_", strlen ("builtin_")) + && !startswith (name + 2, "builtin_") && 0 == memcmp (name + IDENTIFIER_LENGTH (id) - strlen ("_chk"), "_chk", strlen ("_chk") + 1)) /* Treat __*_chk fortification functions as anticipated as well, @@ -7606,9 +7605,9 @@ omp_declare_variant_finalize_one (tree decl, tree attr) return true; } if (fndecl_built_in_p (variant) - && (strncmp (varname, "__builtin_", strlen ("__builtin_")) == 0 - || strncmp (varname, "__sync_", strlen ("__sync_")) == 0 - || strncmp (varname, "__atomic_", strlen ("__atomic_")) == 0)) + && (startswith (varname, "__builtin_") + || startswith (varname, "__sync_") + || startswith (varname, "__atomic_"))) { error_at (varid_loc, "variant %qD is a built-in", variant); return true; @@ -9881,8 +9880,8 @@ grokfndecl (tree ctype, || (IDENTIFIER_LENGTH (declarator) > 10 && IDENTIFIER_POINTER (declarator)[0] == '_' && IDENTIFIER_POINTER (declarator)[1] == '_' - && strncmp (IDENTIFIER_POINTER (declarator)+2, - "builtin_", 8) == 0) + && startswith (IDENTIFIER_POINTER (declarator) + 2, + "builtin_")) || (targetcm.cxx_implicit_extern_c && (targetcm.cxx_implicit_extern_c (IDENTIFIER_POINTER (declarator)))))) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index c88d174..3c2276b 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1138,7 +1138,7 @@ dump_decl_name (cxx_pretty_printer *pp, tree t, int flags) } const char *str = IDENTIFIER_POINTER (t); - if (!strncmp (str, "_ZGR", 4)) + if (startswith (str, "_ZGR")) { pp_cxx_ws_string (pp, ""); return; diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 49f1266..f0e1f41 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1308,10 +1308,10 @@ find_decomp_unqualified_name (tree decl, size_t *len) const char *p = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); const char *end = p + IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (decl)); bool nested = false; - if (strncmp (p, "_Z", 2)) + if (!startswith (p, "_Z")) return NULL; p += 2; - if (!strncmp (p, "St", 2)) + if (startswith (p, "St")) p += 2; else if (*p == 'N') { @@ -1327,7 +1327,7 @@ find_decomp_unqualified_name (tree decl, size_t *len) break; } } - if (strncmp (p, "DC", 2)) + if (!startswith (p, "DC")) return NULL; if (nested) { @@ -4430,7 +4430,7 @@ static void write_guarded_var_name (const tree variable) { if (DECL_NAME (variable) - && strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0) + && startswith (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR")) /* The name of a guard variable for a reference temporary should refer to the reference, not the temporary. */ write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4); @@ -4488,8 +4488,7 @@ decl_tls_wrapper_p (const tree fn) if (TREE_CODE (fn) != FUNCTION_DECL) return false; tree name = DECL_NAME (fn); - return strncmp (IDENTIFIER_POINTER (name), TLS_WRAPPER_PREFIX, - strlen (TLS_WRAPPER_PREFIX)) == 0; + return startswith (IDENTIFIER_POINTER (name), TLS_WRAPPER_PREFIX); } /* Return an identifier for the name of a temporary variable used to diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 58bd6d1..0fe29c6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18668,9 +18668,8 @@ cp_parser_simple_type_specifier (cp_parser* parser, decl_specs->int_n_idx = idx; /* Check if the alternate "__intN__" form has been used instead of "__intN". */ - if (strncmp (IDENTIFIER_POINTER (token->u.value) - + (IDENTIFIER_LENGTH (token->u.value) - 2), - "__", 2) == 0) + if (startswith (IDENTIFIER_POINTER (token->u.value) + + (IDENTIFIER_LENGTH (token->u.value) - 2), "__")) decl_specs->int_n_alt = true; } type = int_n_trees [idx].signed_type; @@ -22961,7 +22960,7 @@ cp_parser_tx_qualifier_opt (cp_parser *parser) tree name = token->u.value; const char *p = IDENTIFIER_POINTER (name); const int len = strlen ("transaction_safe"); - if (!strncmp (p, "transaction_safe", len)) + if (startswith (p, "transaction_safe")) { p += len; if (*p == '\0' diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 36a8cb5..bd99529 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6994,7 +6994,7 @@ bool template_parm_object_p (const_tree t) { return (TREE_CODE (t) == VAR_DECL && DECL_ARTIFICIAL (t) && DECL_NAME (t) - && !strncmp (IDENTIFIER_POINTER (DECL_NAME (t)), "_ZTA", 4)); + && startswith (IDENTIFIER_POINTER (DECL_NAME (t)), "_ZTA")); } /* Subroutine of convert_nontype_argument, to check whether EXPR, as an @@ -28493,8 +28493,7 @@ dguide_name_p (tree name) { return (TREE_CODE (name) == IDENTIFIER_NODE && TREE_TYPE (name) - && !strncmp (IDENTIFIER_POINTER (name), dguide_base, - strlen (dguide_base))); + && startswith (IDENTIFIER_POINTER (name), dguide_base)); } /* True if FN is a deduction guide. */ -- cgit v1.1 From a076632e274abe344ca7648b7c7f299273d4cbe0 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 7 May 2021 09:51:18 +0200 Subject: middle-end/100464 - avoid spurious TREE_ADDRESSABLE in folding debug stmts canonicalize_constructor_val was setting TREE_ADDRESSABLE on bases of ADDR_EXPRs but that's futile when we're dealing with CTOR values in debug stmts. This rips out the code which was added for Java and should have been an assertion when we didn't have debug stmts. To not regress g++.dg/tree-ssa/array-temp1.C we have to adjust the testcase to not look for a no longer applied invalid optimization. 2021-05-10 Richard Biener PR middle-end/100464 PR c++/100468 gcc/ * gimple-fold.c (canonicalize_constructor_val): Do not set TREE_ADDRESSABLE. gcc/cp/ * call.c (set_up_extended_ref_temp): Mark the temporary addressable if the TARGET_EXPR was. gcc/testsuite/ * gcc.dg/pr100464.c: New testcase. * g++.dg/tree-ssa/array-temp1.C: Adjust. --- gcc/cp/call.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index d985e4e..f07e09a 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -12478,6 +12478,8 @@ set_up_extended_ref_temp (tree decl, tree expr, vec **cleanups, VAR. */ if (TREE_CODE (expr) != TARGET_EXPR) expr = get_target_expr (expr); + else if (TREE_ADDRESSABLE (expr)) + TREE_ADDRESSABLE (var) = 1; if (TREE_CODE (decl) == FIELD_DECL && extra_warnings && !TREE_NO_WARNING (decl)) -- cgit v1.1 From aa891c56f25baac94db004e309d1b6e40b770a95 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 11 May 2021 00:16:36 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8bbc030..122808e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,31 @@ +2021-05-10 Richard Biener + + PR middle-end/100464 + PR c++/100468 + * call.c (set_up_extended_ref_temp): Mark the temporary + addressable if the TARGET_EXPR was. + +2021-05-10 Martin Liska + + * decl.c (duplicate_decls): Use startswith + function instead of strncmp. + (cxx_builtin_function): Likewise. + (omp_declare_variant_finalize_one): Likewise. + (grokfndecl): Likewise. + * error.c (dump_decl_name): Likewise. + * mangle.c (find_decomp_unqualified_name): Likewise. + (write_guarded_var_name): Likewise. + (decl_tls_wrapper_p): Likewise. + * parser.c (cp_parser_simple_type_specifier): Likewise. + (cp_parser_tx_qualifier_opt): Likewise. + * pt.c (template_parm_object_p): Likewise. + (dguide_name_p): Likewise. + +2021-05-10 Martin Liska + + PR c++/99616 + * decl.c (grokdeclarator): Remove redundant NULL check. + 2021-05-07 Jason Merrill * tree.c (rvalue): Assert expr is not a class lvalue. -- cgit v1.1 From e7a9f085ffd34b0d7bc4b803c182b41494f609aa Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 10 May 2021 22:33:04 -0400 Subject: c++: fn parm pack expansion inside constraint [PR100138] This PR is about CTAD but the underlying problems are more general; CTAD is a good trigger for them because of the necessary substitution into constraints that deduction guide generation entails. In the testcase below, when generating the implicit deduction guide for the constrained constructor template for A, we substitute the generic flattening map 'tsubst_args' into the constructor's constraints. During this substitution, tsubst_pack_expansion returns a rebuilt pack expansion for sizeof...(xs), but doesn't carry over the PACK_EXPANSION_LOCAL_P (and PACK_EXPANSION_SIZEOF_P) flag from the original tree to the rebuilt one. The flag is otherwise unset on the original tree but gets set for the rebuilt tree from make_pack_expansion since at_function_scope_p() is true (we're inside main). This leads to a crash during satisfaction when substituting into the pack expansion because we don't have local_specializations set up (and it'd be set up for us if PACK_EXPANSION_LOCAL_P is unset) Similarly, tsubst_constraint needs to set cp_unevaluated so that the substitution performed therein doesn't rely on local_specializations. This avoids a crash during CTAD for C below. gcc/cp/ChangeLog: PR c++/100138 * constraint.cc (tsubst_constraint): Set up cp_unevaluated. (satisfy_atom): Set up iloc_sentinel before calling cxx_constant_value. * pt.c (tsubst_pack_expansion): When returning a rebuilt pack expansion, carry over PACK_EXPANSION_LOCAL_P and PACK_EXPANSION_SIZEOF_P from the original pack expansion. gcc/testsuite/ChangeLog: PR c++/100138 * g++.dg/cpp2a/concepts-ctad4.C: New test. --- gcc/cp/constraint.cc | 6 +++++- gcc/cp/pt.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 0709695..30fccc4 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -2747,6 +2747,7 @@ tsubst_constraint (tree t, tree args, tsubst_flags_t complain, tree in_decl) /* We also don't want to evaluate concept-checks when substituting the constraint-expressions of a declaration. */ processing_constraint_expression_sentinel s; + cp_unevaluated u; tree expr = tsubst_expr (t, args, complain, in_decl, false); return expr; } @@ -3005,7 +3006,10 @@ satisfy_atom (tree t, tree args, sat_info info) /* Compute the value of the constraint. */ if (info.noisy ()) - result = cxx_constant_value (result); + { + iloc_sentinel ils (EXPR_LOCATION (result)); + result = cxx_constant_value (result); + } else { result = maybe_constant_value (result, NULL_TREE, diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index bd99529..85c05af 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13203,6 +13203,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, else result = tsubst (pattern, args, complain, in_decl); result = make_pack_expansion (result, complain); + PACK_EXPANSION_LOCAL_P (result) = PACK_EXPANSION_LOCAL_P (t); + PACK_EXPANSION_SIZEOF_P (result) = PACK_EXPANSION_SIZEOF_P (t); if (PACK_EXPANSION_AUTO_P (t)) { /* This is a fake auto... pack expansion created in add_capture with -- cgit v1.1 From 6ab1176667734bd6de20833f8d263c03a418c452 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 10 May 2021 22:38:34 -0400 Subject: c++: dependent operator expression lookup [PR51577] This unconditionally enables the maybe_save_operator_binding mechanism for all function templates, so that when resolving a dependent operator expression from a function template we ignore later-declared namespace-scope bindings that weren't visible at template definition time. This patch additionally makes the mechanism apply to dependent comma and compound-assignment operator expressions. Note that this doesn't fix the testcases in PR83035 or PR99692 because there the dependent operator expressions aren't at function scope. I'm not sure how adapt this mechanism for these testcases, since although we'll in both testcases have a TEMPLATE_DECL to associate the lookup result with, at instantiation time we won't have an appropriate binding level to push to. gcc/cp/ChangeLog: PR c++/51577 * name-lookup.c (maybe_save_operator_binding): Unconditionally enable for all function templates, not just generic lambdas. Handle compound-assignment operator expressions. * typeck.c (build_x_compound_expr): Call maybe_save_operator_binding in the type-dependent case. (build_x_modify_expr): Likewise. Move declaration of 'op' closer to its first use. gcc/testsuite/ChangeLog: PR c++/51577 * g++.dg/lookup/operator-3.C: New test. --- gcc/cp/name-lookup.c | 15 +++++++-------- gcc/cp/typeck.c | 17 ++++++++++++----- 2 files changed, 19 insertions(+), 13 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 4e84e2f..a6c9e68 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -9116,7 +9116,7 @@ static const char *const op_bind_attrname = "operator bindings"; void maybe_save_operator_binding (tree e) { - /* This is only useful in a generic lambda. */ + /* This is only useful in a template. */ if (!processing_template_decl) return; @@ -9124,13 +9124,12 @@ maybe_save_operator_binding (tree e) if (!cfn) return; - /* Do this for lambdas and code that will emit a CMI. In a module's - GMF we don't yet know whether there will be a CMI. */ - if (!module_has_cmi_p () && !global_purview_p () && !current_lambda_expr()) - return; - - tree fnname = ovl_op_identifier (false, TREE_CODE (e)); - if (!fnname) + tree fnname; + if(TREE_CODE (e) == MODOP_EXPR) + fnname = ovl_op_identifier (true, TREE_CODE (TREE_OPERAND (e, 1))); + else + fnname = ovl_op_identifier (false, TREE_CODE (e)); + if (!fnname || fnname == assign_op_identifier) return; tree attributes = DECL_ATTRIBUTES (cfn); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 5af47ce..9002dd1 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -7274,7 +7274,11 @@ build_x_compound_expr (location_t loc, tree op1, tree op2, { if (type_dependent_expression_p (op1) || type_dependent_expression_p (op2)) - return build_min_nt_loc (loc, COMPOUND_EXPR, op1, op2); + { + result = build_min_nt_loc (loc, COMPOUND_EXPR, op1, op2); + maybe_save_operator_binding (result); + return result; + } op1 = build_non_dependent_expr (op1); op2 = build_non_dependent_expr (op2); } @@ -8938,7 +8942,6 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, tree orig_lhs = lhs; tree orig_rhs = rhs; tree overload = NULL_TREE; - tree op = build_nt (modifycode, NULL_TREE, NULL_TREE); if (lhs == error_mark_node || rhs == error_mark_node) return cp_expr (error_mark_node, loc); @@ -8948,9 +8951,12 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, if (modifycode == NOP_EXPR || type_dependent_expression_p (lhs) || type_dependent_expression_p (rhs)) - return build_min_nt_loc (loc, MODOP_EXPR, lhs, - build_min_nt_loc (loc, modifycode, NULL_TREE, - NULL_TREE), rhs); + { + tree op = build_min_nt_loc (loc, modifycode, NULL_TREE, NULL_TREE); + tree rval = build_min_nt_loc (loc, MODOP_EXPR, lhs, op, rhs); + maybe_save_operator_binding (rval); + return rval; + } lhs = build_non_dependent_expr (lhs); rhs = build_non_dependent_expr (rhs); @@ -8958,6 +8964,7 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, if (modifycode != NOP_EXPR) { + tree op = build_nt (modifycode, NULL_TREE, NULL_TREE); tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, op, &overload, complain); if (rval) -- cgit v1.1 From 010d4a5047166037b316ed22331f3d99742f1f1d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 11 May 2021 09:53:20 -0400 Subject: c++: ICE casting class to vector [PR100517] My recent change to reject calling rvalue() with an argument of class type crashes on this testcase, where we use rvalue() on what we expect to be an argument of integer or vector type. Fixed by checking first. gcc/cp/ChangeLog: PR c++/100517 * typeck.c (build_reinterpret_cast_1): Check intype on cast to vector. gcc/testsuite/ChangeLog: PR c++/100517 * g++.dg/ext/vector41.C: New test. --- gcc/cp/typeck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 9002dd1..703ddd3 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -8114,7 +8114,7 @@ build_reinterpret_cast_1 (location_t loc, tree type, tree expr, "pointer-to-object is conditionally-supported"); return build_nop_reinterpret (type, expr); } - else if (gnu_vector_type_p (type)) + else if (gnu_vector_type_p (type) && scalarish_type_p (intype)) return convert_to_vector (type, rvalue (expr)); else if (gnu_vector_type_p (intype) && INTEGRAL_OR_ENUMERATION_TYPE_P (type)) -- cgit v1.1 From 037e36611108283a729d94a8ae15962995742886 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 12 May 2021 08:51:03 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 122808e..80ea065 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,30 @@ +2021-05-11 Jason Merrill + + PR c++/100517 + * typeck.c (build_reinterpret_cast_1): Check intype on + cast to vector. + +2021-05-11 Patrick Palka + + PR c++/51577 + * name-lookup.c (maybe_save_operator_binding): Unconditionally + enable for all function templates, not just generic lambdas. + Handle compound-assignment operator expressions. + * typeck.c (build_x_compound_expr): Call maybe_save_operator_binding + in the type-dependent case. + (build_x_modify_expr): Likewise. Move declaration of 'op' closer + to its first use. + +2021-05-11 Patrick Palka + + PR c++/100138 + * constraint.cc (tsubst_constraint): Set up cp_unevaluated. + (satisfy_atom): Set up iloc_sentinel before calling + cxx_constant_value. + * pt.c (tsubst_pack_expansion): When returning a rebuilt pack + expansion, carry over PACK_EXPANSION_LOCAL_P and + PACK_EXPANSION_SIZEOF_P from the original pack expansion. + 2021-05-10 Richard Biener PR middle-end/100464 -- cgit v1.1 From fa6894ec9ce25f5aff10ec176212383f5c88b1ec Mon Sep 17 00:00:00 2001 From: Marcel Vollweiler Date: Wed, 12 May 2021 09:31:58 -0700 Subject: OpenMP: Add support for 'close' in map clause gcc/c/ChangeLog: * c-parser.c (c_parser_omp_clause_map): Support map-type-modifier 'close'. gcc/cp/ChangeLog: * parser.c (cp_parser_omp_clause_map): Support map-type-modifier 'close'. gcc/testsuite/ChangeLog: * c-c++-common/gomp/map-6.c: New test. * c-c++-common/gomp/map-7.c: New test. --- gcc/cp/parser.c | 90 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 20 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0fe29c6..41df5dd 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -37859,40 +37859,90 @@ cp_parser_omp_clause_depend (cp_parser *parser, tree list, location_t loc) map-kind: alloc | to | from | tofrom | release | delete - map ( always [,] map-kind: variable-list ) */ + map ( always [,] map-kind: variable-list ) + + OpenMP 5.0: + map ( [map-type-modifier[,] ...] map-kind: variable-list ) + + map-type-modifier: + always | close */ static tree cp_parser_omp_clause_map (cp_parser *parser, tree list) { tree nlist, c; enum gomp_map_kind kind = GOMP_MAP_TOFROM; - bool always = false; if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + int pos = 1; + int map_kind_pos = 0; + while (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_NAME + || cp_lexer_peek_nth_token (parser->lexer, pos)->keyword == RID_DELETE) { - tree id = cp_lexer_peek_token (parser->lexer)->u.value; - const char *p = IDENTIFIER_POINTER (id); + if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COLON) + { + map_kind_pos = pos; + break; + } + + if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA) + pos++; + pos++; + } + bool always_modifier = false; + bool close_modifier = false; + for (int pos = 1; pos < map_kind_pos; ++pos) + { + cp_token *tok = cp_lexer_peek_token (parser->lexer); + if (tok->type == CPP_COMMA) + { + cp_lexer_consume_token (parser->lexer); + continue; + } + + const char *p = IDENTIFIER_POINTER (tok->u.value); if (strcmp ("always", p) == 0) { - int nth = 2; - if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COMMA) - nth++; - if ((cp_lexer_peek_nth_token (parser->lexer, nth)->type == CPP_NAME - || (cp_lexer_peek_nth_token (parser->lexer, nth)->keyword - == RID_DELETE)) - && (cp_lexer_peek_nth_token (parser->lexer, nth + 1)->type - == CPP_COLON)) + if (always_modifier) { - always = true; - cp_lexer_consume_token (parser->lexer); - if (nth == 3) - cp_lexer_consume_token (parser->lexer); + cp_parser_error (parser, "too many % modifiers"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + always_modifier = true; + } + else if (strcmp ("close", p) == 0) + { + if (close_modifier) + { + cp_parser_error (parser, "too many % modifiers"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; } + close_modifier = true; } + else + { + cp_parser_error (parser, "%<#pragma omp target%> with " + "modifier other than % or %" + "on % clause"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + + cp_lexer_consume_token (parser->lexer); } if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) @@ -37904,11 +37954,11 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) if (strcmp ("alloc", p) == 0) kind = GOMP_MAP_ALLOC; else if (strcmp ("to", p) == 0) - kind = always ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO; + kind = always_modifier ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO; else if (strcmp ("from", p) == 0) - kind = always ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM; + kind = always_modifier ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM; else if (strcmp ("tofrom", p) == 0) - kind = always ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM; + kind = always_modifier ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM; else if (strcmp ("release", p) == 0) kind = GOMP_MAP_RELEASE; else -- cgit v1.1 From 3a2b12bc5a7da7f0c5cf2ef4879d435a02feda8d Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 12 May 2021 11:19:13 -0400 Subject: c++: Disable -Wint-in-bool-context in instantiations This warning is of questionable value when it's emitted when instantiating a template, as in the following testcase. It could be silenced by writing hb(i) << 1 instead of 2 * hb(i) but that's unnecessary obfuscation. gcc/cp/ChangeLog: * pt.c (tsubst_copy_and_build): Add warn_int_in_bool_context sentinel. gcc/testsuite/ChangeLog: * g++.dg/warn/Wint-in-bool-context-2.C: New test. --- gcc/cp/pt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 85c05af..d7d6a3f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -19801,6 +19801,7 @@ tsubst_copy_and_build (tree t, warning_sentinel s(warn_useless_cast); warning_sentinel s2(warn_ignored_qualifiers); + warning_sentinel s3(warn_int_in_bool_context); switch (TREE_CODE (t)) { case CAST_EXPR: -- cgit v1.1 From 0ff3a0f2b9d5cbea70d134cda2e74b674f8be9c9 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 13 May 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 80ea065..5a8a650 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2021-05-12 Marek Polacek + + * pt.c (tsubst_copy_and_build): Add warn_int_in_bool_context + sentinel. + +2021-05-12 Marcel Vollweiler + + * parser.c (cp_parser_omp_clause_map): Support map-type-modifier + 'close'. + 2021-05-11 Jason Merrill PR c++/100517 -- cgit v1.1 From 149061188c7c6ddf27663c8c00b7574fc8d0fd23 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 29 Apr 2021 21:38:14 -0400 Subject: c++: Check attributes on friend declarations [PR99032] This patch implements [dcl.attr.grammar]/5: "If an attribute-specifier-seq appertains to a friend declaration ([class.friend]), that declaration shall be a definition." This restriction applies to C++11-style attributes as well as GNU attributes with the exception that we allow GNU attributes that require a type, such as vector_size to continue accepting code as in attrib63.C. There are various forms of friend declarations, we have friend templates, C++11 extended friend declarations, and so on. In some cases we already ignore the attribute and warn that it was ignored. But certain cases weren't diagnosed, and with this patch we'll give a hard error. I tried hard not to emit both a warning and error and I think it worked out. Jason provided the cp_parser_decl_specifier_seq hunk to detect using standard attributes in the middle of decl-specifiers, which is invalid. Co-authored-by: Jason Merrill gcc/cp/ChangeLog: PR c++/99032 * cp-tree.h (any_non_type_attribute_p): Declare. * decl.c (grokdeclarator): Diagnose when an attribute appertains to a friend declaration that is not a definition. * decl2.c (any_non_type_attribute_p): New. * parser.c (cp_parser_decl_specifier_seq): Diagnose standard attributes in the middle of decl-specifiers. (cp_parser_elaborated_type_specifier): Diagnose when an attribute appertains to a friend declaration that is not a definition. (cp_parser_member_declaration): Likewise. gcc/testsuite/ChangeLog: PR c++/99032 * g++.dg/cpp0x/friend7.C: New test. * g++.dg/cpp0x/gen-attrs-4.C: Add dg-error. * g++.dg/cpp0x/gen-attrs-39-1.C: Likewise. * g++.dg/cpp0x/gen-attrs-74.C: New test. * g++.dg/ext/attrib63.C: New test. --- gcc/cp/cp-tree.h | 1 + gcc/cp/decl.c | 5 +++++ gcc/cp/decl2.c | 14 ++++++++++++++ gcc/cp/parser.c | 23 ++++++++++++++++++++++- 4 files changed, 42 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 122dadf..580db91 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6763,6 +6763,7 @@ extern tree grokbitfield (const cp_declarator *, cp_decl_specifier_seq *, tree, tree, tree); extern tree splice_template_attributes (tree *, tree); extern bool any_dependent_type_attributes_p (tree); +extern bool any_non_type_attribute_p (tree); extern tree cp_reconstruct_complex_type (tree, tree); extern bool attributes_naming_typedef_ok (tree); extern void cplus_decl_attributes (tree *, tree, int); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index bc3928d..17511f0 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13741,6 +13741,11 @@ grokdeclarator (const cp_declarator *declarator, if (friendp) { + if (attrlist && !funcdef_flag + /* Hack to allow attributes like vector_size on a friend. */ + && any_non_type_attribute_p (*attrlist)) + error_at (id_loc, "attribute appertains to a friend " + "declaration that is not a definition"); /* Friends are treated specially. */ if (ctype == current_class_type) ; /* We already issued a permerror. */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 89f874a..8e4dd6b 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1331,6 +1331,20 @@ any_dependent_type_attributes_p (tree attrs) return false; } +/* True if ATTRS contains any attribute that does not require a type. */ + +bool +any_non_type_attribute_p (tree attrs) +{ + for (tree a = attrs; a; a = TREE_CHAIN (a)) + { + const attribute_spec *as = lookup_attribute_spec (get_attribute_name (a)); + if (as && !as->type_required) + return true; + } + return false; +} + /* Return true iff ATTRS are acceptable attributes to be applied in-place to a typedef which gives a previously unnamed class or enum a name for linkage purposes. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 41df5dd..c0b5795 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -15146,6 +15146,16 @@ cp_parser_decl_specifier_seq (cp_parser* parser, if (!found_decl_spec) break; + if (decl_specs->std_attributes) + { + error_at (decl_specs->locations[ds_std_attribute], + "standard attributes in middle of decl-specifiers"); + inform (decl_specs->locations[ds_std_attribute], + "standard attributes must precede the decl-specifiers to " + "apply to the declaration, or follow them to apply to " + "the type"); + } + decl_specs->any_specifiers_p = true; /* After we see one decl-specifier, further decl-specifiers are always optional. */ @@ -19764,11 +19774,15 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, && ! processing_explicit_instantiation) warning (OPT_Wattributes, "attributes ignored on template instantiation"); + else if (is_friend && attributes) + error ("attribute appertains to a friend declaration that is not " + "a definition"); else if (is_declaration && cp_parser_declares_only_class_p (parser)) cplus_decl_attributes (&type, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); else warning (OPT_Wattributes, - "attributes ignored on elaborated-type-specifier that is not a forward declaration"); + "attributes ignored on elaborated-type-specifier that is " + "not a forward declaration"); } if (tag_type == enum_type) @@ -26054,6 +26068,13 @@ cp_parser_member_declaration (cp_parser* parser) error_at (decl_spec_token_start->location, "friend declaration does not name a class or " "function"); + /* Give an error if an attribute cannot appear here, as per + [dcl.attr.grammar]/5. But not when declares_class_or_enum: + we ignore attributes in elaborated-type-specifiers. */ + else if (!declares_class_or_enum && decl_specifiers.attributes) + error_at (decl_spec_token_start->location, + "attribute appertains to a friend declaration " + "that is not a definition"); else make_friend_class (current_class_type, type, /*complain=*/true); -- cgit v1.1 From 2f1bb00ba340e53663651be7874011fd54e1d085 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 5 Apr 2021 11:47:50 -0400 Subject: c++: simplify enclosing_instantiation_of [PR95870] Comparing DECL_SOURCE_LOCATION like the GCC 11 patch for PR 95870 will also work for user-defined functions, if we update their location when instantiating. Another option would be to use LAMBDA_EXPR_REGEN_INFO for lambdas, but this way is even simpler. gcc/cp/ChangeLog: PR c++/95870 * pt.c (enclosing_instantiation_of): Just compare DECL_SOURCE_LOCATION. (regenerate_decl_from_template): Copy DECL_SOURCE_LOCATION. --- gcc/cp/pt.c | 54 ++++++++++++------------------------------------------ 1 file changed, 12 insertions(+), 42 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d7d6a3f..bf99635 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -14437,55 +14437,22 @@ most_general_lambda (tree t) } /* We're instantiating a variable from template function TCTX. Return the - corresponding current enclosing scope. This gets complicated because lambda - functions in templates are regenerated rather than instantiated, but generic - lambda functions are subsequently instantiated. */ + corresponding current enclosing scope. We can match them up using + DECL_SOURCE_LOCATION because lambdas only ever have one source location, and + the DECL_SOURCE_LOCATION for a function instantiation is updated to match + the template definition in regenerate_decl_from_template. */ static tree -enclosing_instantiation_of (tree otctx) +enclosing_instantiation_of (tree tctx) { - tree tctx = otctx; tree fn = current_function_decl; - int lambda_count = 0; - for (; tctx && (lambda_fn_in_template_p (tctx) - || regenerated_lambda_fn_p (tctx)); - tctx = decl_function_context (tctx)) - ++lambda_count; - - if (!tctx) - { - /* Match using DECL_SOURCE_LOCATION, which is unique for all lambdas. - - For GCC 11 the above condition limits this to the previously failing - case where all enclosing functions are lambdas (95870). FIXME. */ - for (tree ofn = fn; ofn; ofn = decl_function_context (ofn)) - if (DECL_SOURCE_LOCATION (ofn) == DECL_SOURCE_LOCATION (otctx)) - return ofn; - gcc_unreachable (); - } + /* We shouldn't ever need to do this for other artificial functions. */ + gcc_assert (!DECL_ARTIFICIAL (tctx) || LAMBDA_FUNCTION_P (tctx)); for (; fn; fn = decl_function_context (fn)) - { - tree ofn = fn; - int flambda_count = 0; - for (; fn && regenerated_lambda_fn_p (fn); - fn = decl_function_context (fn)) - ++flambda_count; - if ((fn && DECL_TEMPLATE_INFO (fn)) - ? most_general_template (fn) != most_general_template (tctx) - : fn != tctx) - continue; - if (flambda_count != lambda_count) - { - gcc_assert (flambda_count > lambda_count); - for (; flambda_count > lambda_count; --flambda_count) - ofn = decl_function_context (ofn); - } - gcc_assert (DECL_NAME (ofn) == DECL_NAME (otctx) - || DECL_CONV_FN_P (ofn)); - return ofn; - } + if (DECL_SOURCE_LOCATION (fn) == DECL_SOURCE_LOCATION (tctx)) + return fn; gcc_unreachable (); } @@ -25492,6 +25459,9 @@ regenerate_decl_from_template (tree decl, tree tmpl, tree args) int args_depth; int parms_depth; + /* Use the source location of the definition. */ + DECL_SOURCE_LOCATION (decl) = DECL_SOURCE_LOCATION (tmpl); + args_depth = TMPL_ARGS_DEPTH (args); parms_depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)); if (args_depth > parms_depth) -- cgit v1.1 From 87a7d10c2e9ec34a276e6acb5d2282a35b9cfafb Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 15 May 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5a8a650..48425b9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,24 @@ +2021-05-14 Jason Merrill + + PR c++/95870 + * pt.c (enclosing_instantiation_of): Just compare + DECL_SOURCE_LOCATION. + (regenerate_decl_from_template): Copy DECL_SOURCE_LOCATION. + +2021-05-14 Marek Polacek + Jason Merrill + + PR c++/99032 + * cp-tree.h (any_non_type_attribute_p): Declare. + * decl.c (grokdeclarator): Diagnose when an attribute appertains to + a friend declaration that is not a definition. + * decl2.c (any_non_type_attribute_p): New. + * parser.c (cp_parser_decl_specifier_seq): Diagnose standard attributes + in the middle of decl-specifiers. + (cp_parser_elaborated_type_specifier): Diagnose when an attribute + appertains to a friend declaration that is not a definition. + (cp_parser_member_declaration): Likewise. + 2021-05-12 Marek Polacek * pt.c (tsubst_copy_and_build): Add warn_int_in_bool_context -- cgit v1.1 From 5d93261bc03c9c6891ccd8c77ab22b2a09971905 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 17 May 2021 10:53:56 +0100 Subject: c++: Fix diagnostic for binding lvalue reference to volatile rvalue [PR 100635] The current diagnostic assumes the reference binding fails because the reference is non-const, but it can also fail if the rvalue is volatile. Use the current diagnostic for non-const cases, and a modified diagnostic otherwise. gcc/cp/ChangeLog: PR c++/100635 * call.c (convert_like_internal): Print different diagnostic if the lvalue reference is const. gcc/testsuite/ChangeLog: * g++.dg/conversion/pr100635.C: New test. --- gcc/cp/call.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index f07e09a..1e2d1d4 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -7900,9 +7900,13 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, "type %qH to a value of type %qI", totype, next->type); } - else + else if (!CP_TYPE_CONST_P (TREE_TYPE (ref_type))) error_at (loc, "cannot bind non-const lvalue reference of " "type %qH to an rvalue of type %qI", totype, extype); + else // extype is volatile + error_at (loc, "cannot bind lvalue reference of type " + "%qH to an rvalue of type %qI", totype, + extype); } else if (!reference_compatible_p (TREE_TYPE (totype), extype)) { -- cgit v1.1 From a7ffc1ef6e38c01037c8894a6bc1889d6f875444 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 18 May 2021 00:16:40 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 48425b9..45af840 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2021-05-17 Jonathan Wakely + + PR c++/100635 + * call.c (convert_like_internal): Print different diagnostic if + the lvalue reference is const. + 2021-05-14 Jason Merrill PR c++/95870 -- cgit v1.1 From 720dff974ea0487c35c0a4bfa527f30df5066ce1 Mon Sep 17 00:00:00 2001 From: Andreas Krebbel Date: Tue, 27 Apr 2021 10:09:06 +0200 Subject: PR100281 C++: Fix SImode pointer handling The problem appears to be triggered by two locations in the front-end where non-POINTER_SIZE pointers aren't handled right now. 1. An assertion in strip_typedefs is triggered because the alignment of the types don't match. This in turn is caused by creating the new type with build_pointer_type instead of taking the type of the original pointer into account. 2. An assertion in cp_convert_to_pointer is triggered which expects the target type to always have POINTER_SIZE. gcc/cp/ChangeLog: PR c++/100281 * cvt.c (cp_convert_to_pointer): Use the size of the target pointer type. * tree.c (cp_build_reference_type): Call cp_build_reference_type_for_mode with VOIDmode. (cp_build_reference_type_for_mode): Rename from cp_build_reference_type. Add MODE argument and invoke build_reference_type_for_mode. (strip_typedefs): Use build_pointer_type_for_mode and cp_build_reference_type_for_mode for pointers and references. gcc/ChangeLog: PR c++/100281 * tree.c (build_reference_type_for_mode) (build_pointer_type_for_mode): Pick pointer mode if MODE argument is VOIDmode. (build_reference_type, build_pointer_type): Invoke build_*_type_for_mode with VOIDmode. gcc/testsuite/ChangeLog: PR c++/100281 * g++.target/s390/pr100281-1.C: New test. * g++.target/s390/pr100281-2.C: New test. --- gcc/cp/cvt.c | 2 +- gcc/cp/tree.c | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index f1687e8..7fa6e8d 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -232,7 +232,7 @@ cp_convert_to_pointer (tree type, tree expr, bool dofold, { if (TYPE_PRECISION (intype) == POINTER_SIZE) return build1 (CONVERT_EXPR, type, expr); - expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr, + expr = cp_convert (c_common_type_for_size (TYPE_PRECISION (type), 0), expr, complain); /* Modes may be different but sizes should be the same. There is supposed to be some integral type that is the same width diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 7f148b4..35faeff 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1206,12 +1206,14 @@ vla_type_p (tree t) return false; } -/* Return a reference type node referring to TO_TYPE. If RVAL is + +/* Return a reference type node of MODE referring to TO_TYPE. If MODE + is VOIDmode the standard pointer mode will be picked. If RVAL is true, return an rvalue reference type, otherwise return an lvalue reference type. If a type node exists, reuse it, otherwise create a new one. */ tree -cp_build_reference_type (tree to_type, bool rval) +cp_build_reference_type_for_mode (tree to_type, machine_mode mode, bool rval) { tree lvalue_ref, t; @@ -1224,7 +1226,8 @@ cp_build_reference_type (tree to_type, bool rval) to_type = TREE_TYPE (to_type); } - lvalue_ref = build_reference_type (to_type); + lvalue_ref = build_reference_type_for_mode (to_type, mode, false); + if (!rval) return lvalue_ref; @@ -1250,7 +1253,7 @@ cp_build_reference_type (tree to_type, bool rval) SET_TYPE_STRUCTURAL_EQUALITY (t); else if (TYPE_CANONICAL (to_type) != to_type) TYPE_CANONICAL (t) - = cp_build_reference_type (TYPE_CANONICAL (to_type), rval); + = cp_build_reference_type_for_mode (TYPE_CANONICAL (to_type), mode, rval); else TYPE_CANONICAL (t) = t; @@ -1260,6 +1263,16 @@ cp_build_reference_type (tree to_type, bool rval) } +/* Return a reference type node referring to TO_TYPE. If RVAL is + true, return an rvalue reference type, otherwise return an lvalue + reference type. If a type node exists, reuse it, otherwise create + a new one. */ +tree +cp_build_reference_type (tree to_type, bool rval) +{ + return cp_build_reference_type_for_mode (to_type, VOIDmode, rval); +} + /* Returns EXPR cast to rvalue reference type, like std::move. */ tree @@ -1561,11 +1574,11 @@ strip_typedefs (tree t, bool *remove_attributes, unsigned int flags) { case POINTER_TYPE: type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags); - result = build_pointer_type (type); + result = build_pointer_type_for_mode (type, TYPE_MODE (t), false); break; case REFERENCE_TYPE: type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags); - result = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t)); + result = cp_build_reference_type_for_mode (type, TYPE_MODE (t), TYPE_REF_IS_RVALUE (t)); break; case OFFSET_TYPE: t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t), remove_attributes, flags); -- cgit v1.1 From f71ca97def69b8aeb046d716eaea2367736f505e Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 18 May 2021 12:06:36 -0400 Subject: c++: "perfect" implicitly deleted move [PR100644] Here we were ignoring the template constructor because the implicit move constructor had all perfect conversions. But CWG1402 says that an implicitly deleted move constructor is ignored by overload resolution; we implement that instead by preferring any other candidate in joust, to get better diagnostics, but that means we need to handle that case here as well. gcc/cp/ChangeLog: PR c++/100644 * call.c (perfect_candidate_p): An implicitly deleted move is not perfect. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/implicit-delete1.C: New test. --- gcc/cp/call.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 1e2d1d4..4a59b97 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5890,6 +5890,11 @@ perfect_candidate_p (z_candidate *cand) { if (cand->viable < 1) return false; + /* CWG1402 makes an implicitly deleted move op worse than other + candidates. */ + if (DECL_DELETED_FN (cand->fn) && DECL_DEFAULTED_FN (cand->fn) + && move_fn_p (cand->fn)) + return false; int len = cand->num_convs; for (int i = 0; i < len; ++i) if (!perfect_conversion_p (cand->convs[i])) -- cgit v1.1 From fef7c8990da15493110118554adfc9a0b779604c Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 11 Mar 2021 14:01:52 -0500 Subject: c++: Prune dead functions. I was looking at the LCOV coverage report for the C++ FE and found a bunch of unused functions that I think we can remove. Obviously, I left alone various dump_* and debug_* routines. I haven't removed cp_build_function_call although it is also currently unused. * lambda_return_type: was used in parser.c in GCC 7, unused since r255950, * classtype_has_non_deleted_copy_ctor: appeared in GCC 10, its usage was removed in c++/95350, * contains_wildcard_p: used in GCC 9, unused since r276764, * get_template_head_requirements: seems to never have been used, * check_constrained_friend: seems to never have been used, * subsumes_constraints: unused since r276764, * push_void_library_fn: usage removed in r248328, * get_template_parms_at_level: unused since r157857, * get_pattern_parm: unused since r275387. (Some of the seemingly unused functions, such as set_global_friend, are actually used in libcc1.) gcc/cp/ChangeLog: * class.c (classtype_has_non_deleted_copy_ctor): Remove. * constraint.cc (contains_wildcard_p): Likewise. (get_template_head_requirements): Likewise. (check_constrained_friend): Likewise. (subsumes_constraints): Likewise. * cp-tree.h (classtype_has_non_deleted_copy_ctor): Likewise. (push_void_library_fn): Likewise. (get_pattern_parm): Likewise. (get_template_parms_at_level): Likewise. (lambda_return_type): Likewise. (get_template_head_requirements): Likewise. (check_constrained_friend): Likewise. (subsumes_constraints): Likewise. * decl.c (push_void_library_fn): Likewise. * lambda.c (lambda_return_type): Likewise. * pt.c (get_template_parms_at_level): Likewise. (get_pattern_parm): Likewise. --- gcc/cp/class.c | 13 ----------- gcc/cp/constraint.cc | 62 ---------------------------------------------------- gcc/cp/cp-tree.h | 8 ------- gcc/cp/decl.c | 10 --------- gcc/cp/lambda.c | 18 --------------- gcc/cp/pt.c | 49 ----------------------------------------- 6 files changed, 160 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 66bc1ee..354addd 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5604,19 +5604,6 @@ classtype_has_non_deleted_move_ctor (tree t) return false; } -/* True iff T has a copy constructor that is not deleted. */ - -bool -classtype_has_non_deleted_copy_ctor (tree t) -{ - if (CLASSTYPE_LAZY_COPY_CTOR (t)) - lazily_declare_fn (sfk_copy_constructor, t); - for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter) - if (copy_fn_p (*iter) && !DECL_DELETED_FN (*iter)) - return true; - return false; -} - /* If T, a class, has a user-provided copy constructor, copy assignment operator, or destructor, returns that function. Otherwise, null. */ diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 30fccc4..03ce8eb 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -278,21 +278,6 @@ get_concept_check_template (tree t) return tmpl; } -/* Returns true if any of the arguments in the template argument list is - a wildcard or wildcard pack. */ - -bool -contains_wildcard_p (tree args) -{ - for (int i = 0; i < TREE_VEC_LENGTH (args); ++i) - { - tree arg = TREE_VEC_ELT (args, i); - if (TREE_CODE (arg) == WILDCARD_DECL) - return true; - } - return false; -} - /*--------------------------------------------------------------------------- Resolution of qualified concept names ---------------------------------------------------------------------------*/ @@ -1310,18 +1295,6 @@ maybe_substitute_reqs_for (tree reqs, const_tree decl_) return reqs; } -/* Returns the template-head requires clause for the template - declaration T or NULL_TREE if none. */ - -tree -get_template_head_requirements (tree t) -{ - tree ci = get_constraints (t); - if (!ci) - return NULL_TREE; - return CI_TEMPLATE_REQS (ci); -} - /* Returns the trailing requires clause of the declarator of a template declaration T or NULL_TREE if none. */ @@ -3469,31 +3442,6 @@ check_function_concept (tree fn) return NULL_TREE; } - -// Check that a constrained friend declaration function declaration, -// FN, is admissible. This is the case only when the declaration depends -// on template parameters and does not declare a specialization. -void -check_constrained_friend (tree fn, tree reqs) -{ - if (fn == error_mark_node) - return; - gcc_assert (TREE_CODE (fn) == FUNCTION_DECL); - - // If there are not constraints, this cannot be an error. - if (!reqs) - return; - - // Constrained friend functions that don't depend on template - // arguments are effectively meaningless. - if (!uses_template_parms (TREE_TYPE (fn))) - { - error_at (location_of (fn), - "constrained friend does not depend on template parameters"); - return; - } -} - /*--------------------------------------------------------------------------- Equivalence of constraints ---------------------------------------------------------------------------*/ @@ -3521,16 +3469,6 @@ equivalently_constrained (tree d1, tree d2) Partial ordering of constraints ---------------------------------------------------------------------------*/ -/* Returns true when the constraints in A subsume those in B. */ - -bool -subsumes_constraints (tree a, tree b) -{ - gcc_assert (!a || TREE_CODE (a) == CONSTRAINT_INFO); - gcc_assert (!b || TREE_CODE (b) == CONSTRAINT_INFO); - return subsumes (a, b); -} - /* Returns true when the constraints in CI strictly subsume the associated constraints of TMPL. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 580db91..3c900dc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6568,7 +6568,6 @@ extern bool type_has_constexpr_destructor (tree); extern bool type_has_virtual_destructor (tree); extern bool classtype_has_move_assign_or_move_ctor_p (tree, bool user_declared); extern bool classtype_has_non_deleted_move_ctor (tree); -extern bool classtype_has_non_deleted_copy_ctor (tree); extern tree classtype_has_depr_implicit_copy (tree); extern bool classtype_has_op (tree, tree_code); extern tree classtype_has_defaulted_op (tree, tree_code); @@ -6654,7 +6653,6 @@ extern void pop_abi_namespace (unsigned flags, extern tree build_library_fn_ptr (const char *, tree, int); extern tree build_cp_library_fn_ptr (const char *, tree, int); extern tree push_library_fn (tree, tree, tree, int); -extern tree push_void_library_fn (tree, tree, int); extern tree push_throw_library_fn (tree, tree); extern void warn_misplaced_attr_for_class_type (location_t location, tree class_type); @@ -7179,7 +7177,6 @@ extern tree get_template_info (const_tree); extern int template_class_depth (tree); extern int is_specialization_of (tree, tree); extern bool is_specialization_of_friend (tree, tree); -extern tree get_pattern_parm (tree, tree); extern int comp_template_args (tree, tree, tree * = NULL, tree * = NULL, bool = false); extern int template_args_equal (tree, tree, bool = false); @@ -7253,7 +7250,6 @@ bool template_template_parameter_p (const_tree); bool template_type_parameter_p (const_tree); extern bool primary_template_specialization_p (const_tree); extern tree get_primary_template_innermost_parameters (const_tree); -extern tree get_template_parms_at_level (tree, int); extern tree get_template_innermost_arguments (const_tree); extern tree get_template_argument_pack_elems (const_tree); extern tree get_function_template_decl (const_tree); @@ -7556,7 +7552,6 @@ extern tree build_lambda_expr (void); extern tree build_lambda_object (tree); extern tree begin_lambda_type (tree); extern tree lambda_capture_field_type (tree, bool, bool); -extern tree lambda_return_type (tree); extern tree lambda_proxy_type (tree); extern tree lambda_function (tree); extern void apply_deduced_return_type (tree, tree); @@ -8109,7 +8104,6 @@ extern tree current_template_constraints (void); extern tree associate_classtype_constraints (tree); extern tree build_constraints (tree, tree); extern tree maybe_substitute_reqs_for (tree, const_tree); -extern tree get_template_head_requirements (tree); extern tree get_trailing_function_requirements (tree); extern tree get_shorthand_constraints (tree); @@ -8135,7 +8129,6 @@ extern tree finish_simple_requirement (location_t, tree); extern tree finish_type_requirement (location_t, tree); extern tree finish_compound_requirement (location_t, tree, tree, bool); extern tree finish_nested_requirement (location_t, tree); -extern void check_constrained_friend (tree, tree); extern tree tsubst_requires_expr (tree, tree, tsubst_flags_t, tree); extern tree evaluate_requires_expr (tree); extern tree tsubst_constraint (tree, tree, tsubst_flags_t, tree); @@ -8159,7 +8152,6 @@ extern bool save_subsumption_result (tree, tree, bool); extern tree find_template_parameters (tree, tree); extern bool equivalent_constraints (tree, tree); extern bool equivalently_constrained (tree, tree); -extern bool subsumes_constraints (tree, tree); extern bool strictly_subsumes (tree, tree); extern bool weakly_subsumes (tree, tree); extern int more_constrained (tree, tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 17511f0..4f2fc2e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4963,16 +4963,6 @@ push_cp_library_fn (enum tree_code operator_code, tree type, return fn; } -/* Like push_library_fn, but takes a TREE_LIST of parm types rather than - a FUNCTION_TYPE. */ - -tree -push_void_library_fn (tree name, tree parmtypes, int ecf_flags) -{ - tree type = build_function_type (void_type_node, parmtypes); - return push_library_fn (name, type, NULL_TREE, ecf_flags); -} - /* Like push_library_fn, but also note that this function throws and does not return. Used for __throw_foo and the like. */ diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 16e2b4c..4a1e090 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -160,24 +160,6 @@ begin_lambda_type (tree lambda) return type; } -/* Returns the type to use for the return type of the operator() of a - closure class. */ - -tree -lambda_return_type (tree expr) -{ - if (expr == NULL_TREE) - return void_type_node; - if (type_unknown_p (expr) - || BRACE_ENCLOSED_INITIALIZER_P (expr)) - { - cxx_incomplete_type_error (expr, TREE_TYPE (expr)); - return error_mark_node; - } - gcc_checking_assert (!type_dependent_expression_p (expr)); - return cv_unqualified (type_decays_to (unlowered_expr_type (expr))); -} - /* Given a LAMBDA_EXPR or closure type LAMBDA, return the op() of the closure type. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index bf99635..23d2623 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -3693,25 +3693,6 @@ get_primary_template_innermost_parameters (const_tree t) return parms; } -/* Return the template parameters of the LEVELth level from the full list - of template parameters PARMS. */ - -tree -get_template_parms_at_level (tree parms, int level) -{ - tree p; - if (!parms - || TREE_CODE (parms) != TREE_LIST - || level > TMPL_PARMS_DEPTH (parms)) - return NULL_TREE; - - for (p = parms; p; p = TREE_CHAIN (p)) - if (TMPL_PARMS_DEPTH (p) == level) - return p; - - return NULL_TREE; -} - /* Returns the template arguments of T if T is a template instantiation, NULL otherwise. */ @@ -13276,36 +13257,6 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, return result; } -/* Given PARM_DECL PARM, find the corresponding PARM_DECL in the template - TMPL. We do this using DECL_PARM_INDEX, which should work even with - parameter packs; all parms generated from a function parameter pack will - have the same DECL_PARM_INDEX. */ - -tree -get_pattern_parm (tree parm, tree tmpl) -{ - tree pattern = DECL_TEMPLATE_RESULT (tmpl); - tree patparm; - - if (DECL_ARTIFICIAL (parm)) - { - for (patparm = DECL_ARGUMENTS (pattern); - patparm; patparm = DECL_CHAIN (patparm)) - if (DECL_ARTIFICIAL (patparm) - && DECL_NAME (parm) == DECL_NAME (patparm)) - break; - } - else - { - patparm = FUNCTION_FIRST_USER_PARM (DECL_TEMPLATE_RESULT (tmpl)); - patparm = chain_index (DECL_PARM_INDEX (parm)-1, patparm); - gcc_assert (DECL_PARM_INDEX (patparm) - == DECL_PARM_INDEX (parm)); - } - - return patparm; -} - /* Make an argument pack out of the TREE_VEC VEC. */ static tree -- cgit v1.1 From a8daf9a19a5eae6b98acede14bb6c27b2e0038e0 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 19 May 2021 00:16:45 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 45af840..45588a8 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,42 @@ +2021-05-18 Marek Polacek + + * class.c (classtype_has_non_deleted_copy_ctor): Remove. + * constraint.cc (contains_wildcard_p): Likewise. + (get_template_head_requirements): Likewise. + (check_constrained_friend): Likewise. + (subsumes_constraints): Likewise. + * cp-tree.h (classtype_has_non_deleted_copy_ctor): Likewise. + (push_void_library_fn): Likewise. + (get_pattern_parm): Likewise. + (get_template_parms_at_level): Likewise. + (lambda_return_type): Likewise. + (get_template_head_requirements): Likewise. + (check_constrained_friend): Likewise. + (subsumes_constraints): Likewise. + * decl.c (push_void_library_fn): Likewise. + * lambda.c (lambda_return_type): Likewise. + * pt.c (get_template_parms_at_level): Likewise. + (get_pattern_parm): Likewise. + +2021-05-18 Jason Merrill + + PR c++/100644 + * call.c (perfect_candidate_p): An implicitly deleted move + is not perfect. + +2021-05-18 Andreas Krebbel + + PR c++/100281 + * cvt.c (cp_convert_to_pointer): Use the size of the target + pointer type. + * tree.c (cp_build_reference_type): Call + cp_build_reference_type_for_mode with VOIDmode. + (cp_build_reference_type_for_mode): Rename from + cp_build_reference_type. Add MODE argument and invoke + build_reference_type_for_mode. + (strip_typedefs): Use build_pointer_type_for_mode and + cp_build_reference_type_for_mode for pointers and references. + 2021-05-17 Jonathan Wakely PR c++/100635 -- cgit v1.1 From 061fe8c58ac4d436906a404f7fb46b0a6e0d7b4f Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 18 May 2021 17:12:37 -0400 Subject: c++: template template parm pack expansion [PR100372] Here we have a pack expansion of a template template parameter pack, of which the pattern is a TEMPLATE_DECL, which strip_typedefs doesn't want to see. PR c++/100372 gcc/cp/ChangeLog: * tree.c (strip_typedefs): Only look at the pattern of a TYPE_PACK_EXPANSION if it's a type. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/alias-decl-ttp1.C: New test. --- gcc/cp/tree.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 35faeff..72f498f 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1741,13 +1741,18 @@ strip_typedefs (tree t, bool *remove_attributes, unsigned int flags) result = finish_underlying_type (type); break; case TYPE_PACK_EXPANSION: - type = strip_typedefs (PACK_EXPANSION_PATTERN (t), - remove_attributes, flags); - if (type != PACK_EXPANSION_PATTERN (t)) - { - result = copy_node (t); - PACK_EXPANSION_PATTERN (result) = type; - } + { + tree pat = PACK_EXPANSION_PATTERN (t); + if (TYPE_P (pat)) + { + type = strip_typedefs (pat, remove_attributes, flags); + if (type != pat) + { + result = copy_node (t); + PACK_EXPANSION_PATTERN (result) = type; + } + } + } break; default: break; -- cgit v1.1 From 01b2864757540d24c4e717a77b40b29369c064b2 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 18 May 2021 17:15:42 -0400 Subject: c++: ICE with bad definition of decimal32 [PR100261] The change to only look at the global binding for non-classes meant that here, when dealing with decimal32 which is magically mangled like its first non-static data member, we got a collision with the mangling for float. Fixed by also looking up an existing binding for such magical classes. PR c++/100261 gcc/cp/ChangeLog: * rtti.c (get_tinfo_decl_direct): Check TYPE_TRANSPARENT_AGGR. gcc/testsuite/ChangeLog: * g++.dg/dfp/mangle-6.C: New test. --- gcc/cp/rtti.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 5a33b83..82eaa28 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -433,7 +433,7 @@ get_tinfo_decl_direct (tree type, tree name, int pseudo_ix) if (!name) name = mangle_typeinfo_for_type (type); - if (!CLASS_TYPE_P (type)) + if (!CLASS_TYPE_P (type) || TYPE_TRANSPARENT_AGGR (type)) d = get_global_binding (name); if (!d) -- cgit v1.1 From 780e5d4a2bac6eb7566c966a265961c99449cb55 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 19 May 2021 09:21:09 +0200 Subject: openmp: Handle lastprivate on combined target correctly [PR99928] This patch deals with 2 issues: 1) the gimplifier couldn't differentiate between #pragma omp parallel master #pragma omp taskloop simd and #pragma omp parallel master taskloop simd when there is a significant difference for clause handling between the two; as master construct doesn't have any clauses, we don't currently represent it during gimplification by an gimplification omp context at all, so this patch makes sure we don't set OMP_PARALLEL_COMBINED on parallel master when not combined further. If we ever add a separate master context during gimplification, we'd use ORT_COMBINED_MASTER vs. ORT_MASTER (or MASKED probably). 2) lastprivate when combined with target should be map(tofrom:) on the target, this change handles it only when not combined with firstprivate though, that will need further work (similarly to linear or reduction). 2021-05-19 Jakub Jelinek PR middle-end/99928 gcc/ * tree.h (OMP_MASTER_COMBINED): Define. * gimplify.c (gimplify_scan_omp_clauses): Rewrite lastprivate handling for outer combined/composite constructs to a loop. Handle lastprivate on combined target. (gimplify_expr): Formatting fix. gcc/c/ * c-parser.c (c_parser_omp_master): Set OMP_MASTER_COMBINED on master when combined with taskloop. (c_parser_omp_parallel): Don't set OMP_PARALLEL_COMBINED on parallel master when not combined with taskloop. gcc/cp/ * parser.c (cp_parser_omp_master): Set OMP_MASTER_COMBINED on master when combined with taskloop. (cp_parser_omp_parallel): Don't set OMP_PARALLEL_COMBINED on parallel master when not combined with taskloop. gcc/testsuite/ * c-c++-common/gomp/pr99928-2.c: Remove all xfails. * c-c++-common/gomp/pr99928-12.c: New test. --- gcc/cp/parser.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c0b5795..f3503b1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -40922,7 +40922,9 @@ cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok, tree body = finish_omp_structured_block (sb); if (ret == NULL) return ret; - return c_finish_omp_master (loc, body); + ret = c_finish_omp_master (loc, body); + OMP_MASTER_COMBINED (ret) = 1; + return ret; } } if (!flag_openmp) /* flag_openmp_simd */ @@ -41206,7 +41208,16 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, block); if (ret == NULL_TREE) return ret; - OMP_PARALLEL_COMBINED (stmt) = 1; + /* master doesn't have any clauses and during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel master don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel master + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel master taskloop simd lastprivate (x) */ + if (OMP_MASTER_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; return stmt; } else if (strcmp (p, "loop") == 0) -- cgit v1.1 From 32bd0353db37af2cb023e575ed4ce8c944fd9dba Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Wed, 19 May 2021 15:25:36 +0200 Subject: Fix typos. PR testsuite/100658 gcc/cp/ChangeLog: * mangle.c (write_encoding): Fix typos. gcc/jit/ChangeLog: * libgccjit.c (gcc_jit_context_new_function): Fix typos. gcc/testsuite/ChangeLog: * gcc.dg/local1.c: Fix typos. * gcc.dg/ucnid-5-utf8.c: Likewise. * gcc.dg/ucnid-5.c: Likewise. --- gcc/cp/mangle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index f0e1f41..ee14c2d 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -835,7 +835,7 @@ write_encoding (const tree decl) } } -/* Interface to substitution and identifer mangling, used by the +/* Interface to substitution and identifier mangling, used by the module name mangler. */ void -- cgit v1.1 From adcb497bdba499d161d2e5e8de782bdd6f75d62c Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 18 May 2021 16:11:16 -0400 Subject: c++: Relax attribute on friend declaration checking [PR100596] It turned out that there are codebases that profusely use GNU attributes on friend declarations, so we have to dial back our checking and allow them. And for C++11 attributes let's just warn instead of giving errors. PR c++/100596 gcc/cp/ChangeLog: * cp-tree.h (any_non_type_attribute_p): Remove. * decl.c (grokdeclarator): Turn an error into a warning and only warn for standard attributes. * decl2.c (any_non_type_attribute_p): Remove. * parser.c (cp_parser_elaborated_type_specifier): Turn an error into a warning and only warn for standard attributes. (cp_parser_member_declaration): Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/friend7.C: Turn a few dg-warnings into dg-errors. Remove dg-errors for GNU attributes. * g++.dg/ext/attrib63.C: Remove dg-error. * g++.dg/cpp0x/friend8.C: New test. --- gcc/cp/cp-tree.h | 1 - gcc/cp/decl.c | 14 +++++++++----- gcc/cp/decl2.c | 14 -------------- gcc/cp/parser.c | 29 +++++++++++++++++++---------- 4 files changed, 28 insertions(+), 30 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3c900dc..860ed79 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6761,7 +6761,6 @@ extern tree grokbitfield (const cp_declarator *, cp_decl_specifier_seq *, tree, tree, tree); extern tree splice_template_attributes (tree *, tree); extern bool any_dependent_type_attributes_p (tree); -extern bool any_non_type_attribute_p (tree); extern tree cp_reconstruct_complex_type (tree, tree); extern bool attributes_naming_typedef_ok (tree); extern void cplus_decl_attributes (tree *, tree, int); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 4f2fc2e..28052df 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13731,11 +13731,15 @@ grokdeclarator (const cp_declarator *declarator, if (friendp) { - if (attrlist && !funcdef_flag - /* Hack to allow attributes like vector_size on a friend. */ - && any_non_type_attribute_p (*attrlist)) - error_at (id_loc, "attribute appertains to a friend " - "declaration that is not a definition"); + /* Packages tend to use GNU attributes on friends, so we only + warn for standard attributes. */ + if (attrlist && !funcdef_flag && cxx11_attribute_p (*attrlist)) + { + *attrlist = NULL_TREE; + if (warning_at (id_loc, OPT_Wattributes, "attribute ignored")) + inform (id_loc, "an attribute that appertains to a friend " + "declaration that is not a definition is ignored"); + } /* Friends are treated specially. */ if (ctype == current_class_type) ; /* We already issued a permerror. */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 8e4dd6b..89f874a 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1331,20 +1331,6 @@ any_dependent_type_attributes_p (tree attrs) return false; } -/* True if ATTRS contains any attribute that does not require a type. */ - -bool -any_non_type_attribute_p (tree attrs) -{ - for (tree a = attrs; a; a = TREE_CHAIN (a)) - { - const attribute_spec *as = lookup_attribute_spec (get_attribute_name (a)); - if (as && !as->type_required) - return true; - } - return false; -} - /* Return true iff ATTRS are acceptable attributes to be applied in-place to a typedef which gives a previously unnamed class or enum a name for linkage purposes. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index f3503b1..bc0505d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -19774,9 +19774,12 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, && ! processing_explicit_instantiation) warning (OPT_Wattributes, "attributes ignored on template instantiation"); - else if (is_friend && attributes) - error ("attribute appertains to a friend declaration that is not " - "a definition"); + else if (is_friend && cxx11_attribute_p (attributes)) + { + if (warning (OPT_Wattributes, "attribute ignored")) + inform (input_location, "an attribute that appertains to a friend " + "declaration that is not a definition is ignored"); + } else if (is_declaration && cp_parser_declares_only_class_p (parser)) cplus_decl_attributes (&type, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); else @@ -26064,17 +26067,23 @@ cp_parser_member_declaration (cp_parser* parser) if (type && TREE_CODE (type) == TYPE_DECL) type = TREE_TYPE (type); } + /* Warn if an attribute cannot appear here, as per + [dcl.attr.grammar]/5. But not when declares_class_or_enum: + we ignore attributes in elaborated-type-specifiers. */ + if (!declares_class_or_enum + && cxx11_attribute_p (decl_specifiers.attributes)) + { + decl_specifiers.attributes = NULL_TREE; + if (warning_at (decl_spec_token_start->location, + OPT_Wattributes, "attribute ignored")) + inform (decl_spec_token_start->location, "an attribute " + "that appertains to a friend declaration that " + "is not a definition is ignored"); + } if (!type || !TYPE_P (type)) error_at (decl_spec_token_start->location, "friend declaration does not name a class or " "function"); - /* Give an error if an attribute cannot appear here, as per - [dcl.attr.grammar]/5. But not when declares_class_or_enum: - we ignore attributes in elaborated-type-specifiers. */ - else if (!declares_class_or_enum && decl_specifiers.attributes) - error_at (decl_spec_token_start->location, - "attribute appertains to a friend declaration " - "that is not a definition"); else make_friend_class (current_class_type, type, /*complain=*/true); -- cgit v1.1 From 873c5188fd5d2e17430cab1522aa36fa62582ea7 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 18 May 2021 12:16:08 -0400 Subject: c++: implicit deduction guides, protected access Jonathan raised this issue with CWG, and there seems to be general agreement that a deduction guide generated from a constructor should have access to the same names that the constructor has access to. That seems to be as easy as setting DECL_CONTEXT. gcc/cp/ChangeLog: * pt.c (build_deduction_guide): Treat the implicit deduction guide as a member of the class. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction-access1.C: New test. * g++.dg/cpp1z/class-deduction-access2.C: New test. --- gcc/cp/pt.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 23d2623..32cd0b7 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -28803,6 +28803,9 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com DECL_ABSTRACT_ORIGIN (ded_tmpl) = fn_tmpl; if (ci) set_constraints (ded_tmpl, ci); + /* The artificial deduction guide should have same access as the + constructor. */ + DECL_CONTEXT (ded_fn) = type; return ded_tmpl; } -- cgit v1.1 From cd67343703ef4fa61de837f4690eba70d2760825 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 18 May 2021 12:29:33 -0400 Subject: c++: ICE with <=> fallback [PR100367] Here, when genericizing lexicographical_compare_three_way, we haven't yet walked the operands, so (a == a) still sees ADDR_EXPR , but this is after we've changed the type of a to REFERENCE_TYPE. When we try to fold (a == a) by constexpr evaluation, the constexpr code doesn't understand trying to take the address of a reference, and we end up crashing. Fixed by avoiding constexpr evaluation in genericize_spaceship, by using fold_build2 instead of build_new_op on scalar operands. Class operands should have been expanded during parsing. PR c++/100367 PR c++/96299 gcc/cp/ChangeLog: * method.c (genericize_spaceship): Use fold_build2 for scalar operands. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/spaceship-fallback1.C: New test. --- gcc/cp/method.c | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/method.c b/gcc/cp/method.c index f8c9456..dd74523 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1087,7 +1087,8 @@ genericize_spaceship (location_t loc, tree type, tree op0, tree op1) gcc_checking_assert (tag < cc_last); tree r; - if (SCALAR_TYPE_P (TREE_TYPE (op0))) + bool scalar = SCALAR_TYPE_P (TREE_TYPE (op0)); + if (scalar) { op0 = save_expr (op0); op1 = save_expr (op1); @@ -1097,26 +1098,53 @@ genericize_spaceship (location_t loc, tree type, tree op0, tree op1) int flags = LOOKUP_NORMAL; tsubst_flags_t complain = tf_none; + tree comp; if (tag == cc_partial_ordering) { /* op0 == op1 ? equivalent : op0 < op1 ? less : op1 < op0 ? greater : unordered */ tree uo = lookup_comparison_result (tag, type, 3); - tree comp = build_new_op (loc, LT_EXPR, flags, op1, op0, complain); - r = build_conditional_expr (loc, comp, gt, uo, complain); + if (scalar) + { + /* For scalars use the low level operations; using build_new_op causes + trouble with constexpr eval in the middle of genericize (100367). */ + comp = fold_build2 (LT_EXPR, boolean_type_node, op1, op0); + r = fold_build3 (COND_EXPR, type, comp, gt, uo); + } + else + { + comp = build_new_op (loc, LT_EXPR, flags, op1, op0, complain); + r = build_conditional_expr (loc, comp, gt, uo, complain); + } } else /* op0 == op1 ? equal : op0 < op1 ? less : greater */ r = gt; tree lt = lookup_comparison_result (tag, type, 2); - tree comp = build_new_op (loc, LT_EXPR, flags, op0, op1, complain); - r = build_conditional_expr (loc, comp, lt, r, complain); + if (scalar) + { + comp = fold_build2 (LT_EXPR, boolean_type_node, op0, op1); + r = fold_build3 (COND_EXPR, type, comp, lt, r); + } + else + { + comp = build_new_op (loc, LT_EXPR, flags, op0, op1, complain); + r = build_conditional_expr (loc, comp, lt, r, complain); + } tree eq = lookup_comparison_result (tag, type, 0); - comp = build_new_op (loc, EQ_EXPR, flags, op0, op1, complain); - r = build_conditional_expr (loc, comp, eq, r, complain); + if (scalar) + { + comp = fold_build2 (EQ_EXPR, boolean_type_node, op0, op1); + r = fold_build3 (COND_EXPR, type, comp, eq, r); + } + else + { + comp = build_new_op (loc, EQ_EXPR, flags, op0, op1, complain); + r = build_conditional_expr (loc, comp, eq, r, complain); + } return r; } -- cgit v1.1 From 65f32e5d6bbeb93a7d8d121fd56af6555e16d747 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 20 May 2021 00:16:40 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 45588a8..3f7cf15 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,50 @@ +2021-05-19 Jason Merrill + + PR c++/100367 + PR c++/96299 + * method.c (genericize_spaceship): Use fold_build2 for scalar + operands. + +2021-05-19 Jason Merrill + + * pt.c (build_deduction_guide): Treat the implicit deduction guide + as a member of the class. + +2021-05-19 Marek Polacek + + PR c++/100596 + * cp-tree.h (any_non_type_attribute_p): Remove. + * decl.c (grokdeclarator): Turn an error into a warning and only + warn for standard attributes. + * decl2.c (any_non_type_attribute_p): Remove. + * parser.c (cp_parser_elaborated_type_specifier): Turn an error + into a warning and only warn for standard attributes. + (cp_parser_member_declaration): Likewise. + +2021-05-19 Martin Liska + + PR testsuite/100658 + * mangle.c (write_encoding): Fix typos. + +2021-05-19 Jakub Jelinek + + PR middle-end/99928 + * parser.c (cp_parser_omp_master): Set OMP_MASTER_COMBINED on + master when combined with taskloop. + (cp_parser_omp_parallel): Don't set OMP_PARALLEL_COMBINED on + parallel master when not combined with taskloop. + +2021-05-19 Jason Merrill + + PR c++/100261 + * rtti.c (get_tinfo_decl_direct): Check TYPE_TRANSPARENT_AGGR. + +2021-05-19 Jason Merrill + + PR c++/100372 + * tree.c (strip_typedefs): Only look at the pattern of a + TYPE_PACK_EXPANSION if it's a type. + 2021-05-18 Marek Polacek * class.c (classtype_has_non_deleted_copy_ctor): Remove. -- cgit v1.1 From fe9a6614a16b5ea7f12141c50b6b7de984390ed8 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 19 May 2021 16:40:24 -0400 Subject: c++: ICE with using and enum [PR100659] Here the code for 'using enum' is confused by the combination of a using-decl and an enum that are not from 'using enum'; this CONST_DECL is from the normal unscoped enum scoping. PR c++/100659 gcc/cp/ChangeLog: * cp-tree.h (CONST_DECL_USING_P): Check for null TREE_TYPE. gcc/testsuite/ChangeLog: * g++.dg/parse/access13.C: New test. --- gcc/cp/cp-tree.h | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 860ed79..aa20271 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3553,6 +3553,7 @@ struct GTY(()) lang_decl { created by handle_using_decl. */ #define CONST_DECL_USING_P(NODE) \ (TREE_CODE (NODE) == CONST_DECL \ + && TREE_TYPE (NODE) \ && TREE_CODE (TREE_TYPE (NODE)) == ENUMERAL_TYPE \ && DECL_CONTEXT (NODE) != TREE_TYPE (NODE)) -- cgit v1.1 From 75ab8b4829dec8c70470e8225c9add964f71ed74 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 19 May 2021 17:33:21 -0400 Subject: c++: _Complex template parameter [PR100634] We were crashing because invalid_nontype_parm_type_p allowed _Complex template parms, but convert_nontype_argument didn't know what to do for them. Let's just disallow it, people can and should use std::complex instead. PR c++/100634 gcc/cp/ChangeLog: * pt.c (invalid_nontype_parm_type_p): Return true for COMPLEX_TYPE. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/nontype-complex1.C: New test. --- gcc/cp/pt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 32cd0b7..cbd2f3d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -26563,6 +26563,8 @@ invalid_nontype_parm_type_p (tree type, tsubst_flags_t complain) else if (cxx_dialect >= cxx11 && TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM) return false; + else if (TREE_CODE (type) == COMPLEX_TYPE) + /* Fall through. */; else if (VOID_TYPE_P (type)) /* Fall through. */; else if (cxx_dialect >= cxx20) -- cgit v1.1 From ee336ecb2a7161bc28f6c5343d97870a8d15e177 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 19 May 2021 21:35:58 +0100 Subject: c++: Add new warning options for C++ language mismatches This adds new warning flags, enabled by default: -Wc++11-extensions, -Wc++14-extensions, -Wc++17-extensions, -Wc++20-extensions, and -Wc++23-extensions. The names of the flags are copied from Clang, which already has similar options. No new diagnostics are added, but the new OPT_Wxxx variables are used to control existing pedwarns about occurences of new C++ constructs in code using an old C++ standard dialect. This allows several existing warnings that cannot currently be disabled to be controlled by the appropriate -Wno-xxx flag. For example, it will now be possible to disable warnings about using variadic templates in C++98 code, by using the new -Wno-c++11-extensions option. This will allow libstdc++ headers to disable those warnings unconditionally by using diagnostic pragmas, so that they are not emitted even if -Wsystem-headers is used. Some of the affected diagnostics are currently only given when -Wpedantic is used. Now that we have a more specific warning flag, we could consider making them not depend on -Wpedantic, and only on the new flag. This patch does not do that, as it intends to make no changes to what is accepted/rejected by default. The only effect should be that the new option is shown when -fdiagnostics-show-option is active, and that some warnings can be disabled by using the new flags (and for the warnings that previously only dependend on -Wpedantic, it will now be possible to disable just those warnings while still using -Wpedantic for its other benefits). gcc/c-family/ChangeLog: * c.opt (Wc++11-extensions, Wc++14-extensions) (Wc++17-extensions, Wc++20-extensions, Wc++23-extensions): New options. gcc/cp/ChangeLog: * call.c (maybe_warn_array_conv): Use new warning option. * decl.c (mark_inline_variable, grokdeclarator): Likewise. * error.c (maybe_warn_cpp0x): Likewise. * parser.c (cp_parser_primary_expression) (cp_parser_unqualified_id) (cp_parser_pseudo_destructor_name) (cp_parser_lambda_introducer) (cp_parser_lambda_declarator_opt) (cp_parser_selection_statement) (cp_parser_init_statement) (cp_parser_decomposition_declaration) (cp_parser_function_specifier_opt) (cp_parser_static_assert) (cp_parser_namespace_definition) (cp_parser_using_declaration) (cp_parser_asm_definition) (cp_parser_ctor_initializer_opt_and_function_body) (cp_parser_initializer_list) (cp_parser_type_parameter_key) (cp_parser_member_declaration) (cp_parser_try_block) (cp_parser_std_attribute_spec): Likewise. * pt.c (check_template_variable): Likewise. gcc/ChangeLog: * doc/invoke.texi (-Wno-c++11-extensions) (-Wno-c++14-extensions, -Wno-c++17-extensions) (-Wno-c++20-extensions, -Wno-c++23-extensions): Document new options. --- gcc/cp/call.c | 5 +-- gcc/cp/decl.c | 14 ++++---- gcc/cp/error.c | 37 ++++++++++---------- gcc/cp/parser.c | 104 +++++++++++++++++++++++++++++++------------------------- gcc/cp/pt.c | 2 +- 5 files changed, 88 insertions(+), 74 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4a59b97..fa770f2 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -7469,8 +7469,9 @@ maybe_warn_array_conv (location_t loc, conversion *c, tree expr) || TYPE_DOMAIN (type) == NULL_TREE) return; - if (conv_binds_to_array_of_unknown_bound (c)) - pedwarn (loc, OPT_Wpedantic, "conversions to arrays of unknown bound " + if (pedantic && conv_binds_to_array_of_unknown_bound (c)) + pedwarn (loc, OPT_Wc__20_extensions, + "conversions to arrays of unknown bound " "are only available with %<-std=c++20%> or %<-std=gnu++20%>"); } diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 28052df..7c32f09 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -11166,7 +11166,7 @@ mark_inline_variable (tree decl, location_t loc) inlinep = false; } else if (cxx_dialect < cxx17) - pedwarn (loc, 0, "inline variables are only available " + pedwarn (loc, OPT_Wc__17_extensions, "inline variables are only available " "with %<-std=c++17%> or %<-std=gnu++17%>"); if (inlinep) { @@ -12002,13 +12002,13 @@ grokdeclarator (const cp_declarator *declarator, storage_class = sc_none; staticp = 0; } - if (constexpr_p && cxx_dialect < cxx20) + if (constexpr_p && pedantic && cxx_dialect < cxx20) { gcc_rich_location richloc (declspecs->locations[ds_virtual]); richloc.add_range (declspecs->locations[ds_constexpr]); - pedwarn (&richloc, OPT_Wpedantic, "member %qD can be declared both " - "% and % only in %<-std=c++20%> or " - "%<-std=gnu++20%>", dname); + pedwarn (&richloc, OPT_Wc__20_extensions, "member %qD can be " + "declared both % and % only in " + "%<-std=c++20%> or %<-std=gnu++20%>", dname); } } friendp = decl_spec_seq_has_spec_p (declspecs, ds_friend); @@ -12096,7 +12096,7 @@ grokdeclarator (const cp_declarator *declarator, error_at (declspecs->locations[ds_consteval], "structured " "binding declaration cannot be %qs", "consteval"); if (thread_p && cxx_dialect < cxx20) - pedwarn (declspecs->locations[ds_thread], 0, + pedwarn (declspecs->locations[ds_thread], OPT_Wc__20_extensions, "structured binding declaration can be %qs only in " "%<-std=c++20%> or %<-std=gnu++20%>", declspecs->gnu_thread_keyword_p @@ -12118,7 +12118,7 @@ grokdeclarator (const cp_declarator *declarator, break; case sc_static: if (cxx_dialect < cxx20) - pedwarn (loc, 0, + pedwarn (loc, OPT_Wc__20_extensions, "structured binding declaration can be %qs only in " "%<-std=c++20%> or %<-std=gnu++20%>", "static"); break; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 3c2276b..3d5eebd 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -4407,77 +4407,78 @@ maybe_warn_cpp0x (cpp0x_warn_str str) switch (str) { case CPP0X_INITIALIZER_LISTS: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "extended initializer lists " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_EXPLICIT_CONVERSION: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "explicit conversion operators " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_VARIADIC_TEMPLATES: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "variadic templates " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_LAMBDA_EXPR: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "lambda expressions " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_AUTO: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "C++11 auto only available with %<-std=c++11%> or " "%<-std=gnu++11%>"); break; case CPP0X_SCOPED_ENUMS: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "scoped enums only available with %<-std=c++11%> or " "%<-std=gnu++11%>"); break; case CPP0X_DEFAULTED_DELETED: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "defaulted and deleted functions " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_INLINE_NAMESPACES: - pedwarn (input_location, OPT_Wpedantic, - "inline namespaces " - "only available with %<-std=c++11%> or %<-std=gnu++11%>"); + if (pedantic) + pedwarn (input_location, OPT_Wc__11_extensions, + "inline namespaces " + "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_OVERRIDE_CONTROLS: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "override controls (override/final) " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_NSDMI: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "non-static data member initializers " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_USER_DEFINED_LITERALS: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "user-defined literals " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_DELEGATING_CTORS: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "delegating constructors " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_INHERITING_CTORS: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "inheriting constructors " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_ATTRIBUTES: - pedwarn (input_location, 0, - "c++11 attributes " + pedwarn (input_location, OPT_Wc__11_extensions, + "C++11 attributes " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; case CPP0X_REF_QUALIFIER: - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__11_extensions, "ref-qualifiers " "only available with %<-std=c++11%> or %<-std=gnu++11%>"); break; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index bc0505d..48b83d6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -5577,8 +5577,9 @@ cp_parser_primary_expression (cp_parser *parser, expr = cp_parser_fold_expression (parser, expr); if (expr != error_mark_node && cxx_dialect < cxx17) - pedwarn (input_location, 0, "fold-expressions only available " - "with %<-std=c++17%> or %<-std=gnu++17%>"); + pedwarn (input_location, OPT_Wc__17_extensions, + "fold-expressions only available with %<-std=c++17%> " + "or %<-std=gnu++17%>"); } else /* Let the front end know that this expression was @@ -6325,7 +6326,7 @@ cp_parser_unqualified_id (cp_parser* parser, if (cp_parser_is_keyword (token, RID_AUTO)) { if (cxx_dialect < cxx14) - pedwarn (loc, 0, + pedwarn (loc, OPT_Wc__14_extensions, "%<~auto%> only available with " "%<-std=c++14%> or %<-std=gnu++14%>"); cp_lexer_consume_token (parser->lexer); @@ -8353,7 +8354,7 @@ cp_parser_pseudo_destructor_name (cp_parser* parser, && !type_dependent_expression_p (object)) { if (cxx_dialect < cxx14) - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__14_extensions, "%<~auto%> only available with " "%<-std=c++14%> or %<-std=gnu++14%>"); cp_lexer_consume_token (parser->lexer); @@ -11042,8 +11043,9 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) { location_t loc = cp_lexer_peek_token (parser->lexer)->location; if (cxx_dialect < cxx17) - pedwarn (loc, 0, "%<*this%> capture only available with " - "%<-std=c++17%> or %<-std=gnu++17%>"); + pedwarn (loc, OPT_Wc__17_extensions, + "%<*this%> capture only available with " + "%<-std=c++17%> or %<-std=gnu++17%>"); cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer); if (LAMBDA_EXPR_THIS_CAPTURE (lambda_expr)) @@ -11081,7 +11083,8 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) { ellipsis_loc = cp_lexer_peek_token (parser->lexer)->location; if (cxx_dialect < cxx20) - pedwarn (ellipsis_loc, 0, "pack init-capture only available with " + pedwarn (ellipsis_loc, OPT_Wc__20_extensions, + "pack init-capture only available with " "%<-std=c++20%> or %<-std=gnu++20%>"); cp_lexer_consume_token (parser->lexer); init_pack_expansion = true; @@ -11122,7 +11125,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) bool direct, non_constant; /* An explicit initializer exists. */ if (cxx_dialect < cxx14) - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__14_extensions, "lambda capture initializers " "only available with %<-std=c++14%> or %<-std=gnu++14%>"); capture_init_expr = cp_parser_initializer (parser, &direct, @@ -11296,11 +11299,11 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) if (cp_lexer_next_token_is (parser->lexer, CPP_LESS)) { if (cxx_dialect < cxx14) - pedwarn (parser->lexer->next_token->location, 0, + pedwarn (parser->lexer->next_token->location, OPT_Wc__14_extensions, "lambda templates are only available with " "%<-std=c++14%> or %<-std=gnu++14%>"); - else if (cxx_dialect < cxx20) - pedwarn (parser->lexer->next_token->location, OPT_Wpedantic, + else if (pedantic && cxx_dialect < cxx20) + pedwarn (parser->lexer->next_token->location, OPT_Wc__20_extensions, "lambda templates are only available with " "%<-std=c++20%> or %<-std=gnu++20%>"); @@ -11365,10 +11368,11 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) /* Default arguments shall not be specified in the parameter-declaration-clause of a lambda-declarator. */ - if (cxx_dialect < cxx14) + if (pedantic && cxx_dialect < cxx14) for (tree t = param_list; t; t = TREE_CHAIN (t)) if (TREE_PURPOSE (t) && DECL_P (TREE_VALUE (t))) - pedwarn (DECL_SOURCE_LOCATION (TREE_VALUE (t)), OPT_Wpedantic, + pedwarn (DECL_SOURCE_LOCATION (TREE_VALUE (t)), + OPT_Wc__14_extensions, "default argument specified for lambda parameter"); parens.require_close (parser); @@ -11388,7 +11392,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) if (omitted_parms_loc && lambda_specs.any_specifiers_p) { - pedwarn (omitted_parms_loc, 0, + pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, "parameter declaration before lambda declaration " "specifiers only optional with %<-std=c++2b%> or " "%<-std=gnu++2b%>"); @@ -11407,7 +11411,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) tx_qual = cp_parser_tx_qualifier_opt (parser); if (omitted_parms_loc && tx_qual) { - pedwarn (omitted_parms_loc, 0, + pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, "parameter declaration before lambda transaction " "qualifier only optional with %<-std=c++2b%> or " "%<-std=gnu++2b%>"); @@ -11420,7 +11424,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) if (omitted_parms_loc && exception_spec) { - pedwarn (omitted_parms_loc, 0, + pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, "parameter declaration before lambda exception " "specification only optional with %<-std=c++2b%> or " "%<-std=gnu++2b%>"); @@ -11438,7 +11442,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF)) { if (omitted_parms_loc) - pedwarn (omitted_parms_loc, 0, + pedwarn (omitted_parms_loc, OPT_Wc__23_extensions, "parameter declaration before lambda trailing " "return type only optional with %<-std=c++2b%> or " "%<-std=gnu++2b%>"); @@ -12301,8 +12305,9 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, cx = true; cp_token *tok = cp_lexer_consume_token (parser->lexer); if (cxx_dialect < cxx17) - pedwarn (tok->location, 0, "% only available " - "with %<-std=c++17%> or %<-std=gnu++17%>"); + pedwarn (tok->location, OPT_Wc__17_extensions, + "% only available with " + "%<-std=c++17%> or %<-std=gnu++17%>"); } /* Look for the `('. */ @@ -12327,7 +12332,8 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, { tree decl; if (cxx_dialect < cxx17) - pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0, + pedwarn (cp_lexer_peek_token (parser->lexer)->location, + OPT_Wc__17_extensions, "init-statement in selection statements only available " "with %<-std=c++17%> or %<-std=gnu++17%>"); if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) @@ -13398,7 +13404,8 @@ cp_parser_init_statement (cp_parser *parser, tree *decl) if (cxx_dialect < cxx20) { - pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0, + pedwarn (cp_lexer_peek_token (parser->lexer)->location, + OPT_Wc__20_extensions, "range-based % loops with initializer only " "available with %<-std=c++20%> or %<-std=gnu++20%>"); *decl = error_mark_node; @@ -13422,7 +13429,8 @@ cp_parser_init_statement (cp_parser *parser, tree *decl) cp_lexer_consume_token (parser->lexer); is_range_for = true; if (cxx_dialect < cxx11) - pedwarn (cp_lexer_peek_token (parser->lexer)->location, 0, + pedwarn (cp_lexer_peek_token (parser->lexer)->location, + OPT_Wc__11_extensions, "range-based % loops only available with " "%<-std=c++11%> or %<-std=gnu++11%>"); } @@ -14665,8 +14673,9 @@ cp_parser_decomposition_declaration (cp_parser *parser, } if (cxx_dialect < cxx17) - pedwarn (loc, 0, "structured bindings only available with " - "%<-std=c++17%> or %<-std=gnu++17%>"); + pedwarn (loc, OPT_Wc__17_extensions, + "structured bindings only available with " + "%<-std=c++17%> or %<-std=gnu++17%>"); tree pushed_scope; cp_declarator *declarator = make_declarator (cdk_decomp); @@ -15261,7 +15270,7 @@ cp_parser_function_specifier_opt (cp_parser* parser, = G_("types may not be defined in explicit-specifier"); if (cxx_dialect < cxx20) - pedwarn (token->location, 0, + pedwarn (token->location, OPT_Wc__20_extensions, "% only available with %<-std=c++20%> " "or %<-std=gnu++20%>"); @@ -15428,8 +15437,8 @@ cp_parser_static_assert(cp_parser *parser, bool member_p) if (cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN) { - if (cxx_dialect < cxx17) - pedwarn (input_location, OPT_Wpedantic, + if (pedantic && cxx_dialect < cxx17) + pedwarn (input_location, OPT_Wc__17_extensions, "% without a message " "only available with %<-std=c++17%> or %<-std=gnu++17%>"); /* Eat the ')' */ @@ -20418,10 +20427,11 @@ cp_parser_namespace_definition (cp_parser* parser) RID_INLINE); if (nested_inline_p && nested_definition_count != 0) { - if (cxx_dialect < cxx20) + if (pedantic && cxx_dialect < cxx20) pedwarn (cp_lexer_peek_token (parser->lexer)->location, - OPT_Wpedantic, "nested inline namespace definitions only " - "available with %<-std=c++20%> or %<-std=gnu++20%>"); + OPT_Wc__20_extensions, "nested inline namespace " + "definitions only available with %<-std=c++20%> or " + "%<-std=gnu++20%>"); cp_lexer_consume_token (parser->lexer); } @@ -20448,8 +20458,8 @@ cp_parser_namespace_definition (cp_parser* parser) break; } - if (!nested_definition_count && cxx_dialect < cxx17) - pedwarn (input_location, OPT_Wpedantic, + if (!nested_definition_count && pedantic && cxx_dialect < cxx17) + pedwarn (input_location, OPT_Wc__17_extensions, "nested namespace definitions only available with " "%<-std=c++17%> or %<-std=gnu++17%>"); @@ -20708,7 +20718,7 @@ cp_parser_using_declaration (cp_parser* parser, { cp_token *ell = cp_lexer_consume_token (parser->lexer); if (cxx_dialect < cxx17) - pedwarn (ell->location, 0, + pedwarn (ell->location, OPT_Wc__17_extensions, "pack expansion in using-declaration only available " "with %<-std=c++17%> or %<-std=gnu++17%>"); qscope = make_pack_expansion (qscope); @@ -20741,7 +20751,7 @@ cp_parser_using_declaration (cp_parser* parser, { cp_token *comma = cp_lexer_consume_token (parser->lexer); if (cxx_dialect < cxx17) - pedwarn (comma->location, 0, + pedwarn (comma->location, OPT_Wc__17_extensions, "comma-separated list in using-declaration only available " "with %<-std=c++17%> or %<-std=gnu++17%>"); goto again; @@ -21057,9 +21067,10 @@ cp_parser_asm_definition (cp_parser* parser) functions. */ if (parser->in_function_body && DECL_DECLARED_CONSTEXPR_P (current_function_decl) - && (cxx_dialect < cxx20)) - pedwarn (asm_loc, 0, "% in % function only available " - "with %<-std=c++20%> or %<-std=gnu++20%>"); + && cxx_dialect < cxx20) + pedwarn (asm_loc, OPT_Wc__20_extensions, "% in % " + "function only available with %<-std=c++20%> or " + "%<-std=gnu++20%>"); /* Handle the asm-qualifier-list. */ location_t volatile_loc = UNKNOWN_LOCATION; @@ -24131,11 +24142,11 @@ cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser, && cxx_dialect < cxx20) { if (DECL_CONSTRUCTOR_P (current_function_decl)) - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__20_extensions, "function-try-block body of % constructor only " "available with %<-std=c++20%> or %<-std=gnu++20%>"); else - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__20_extensions, "function-try-block body of % function only " "available with %<-std=c++20%> or %<-std=gnu++20%>"); } @@ -24458,8 +24469,8 @@ cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p, || (cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_OPEN_BRACE))) { - if (cxx_dialect < cxx20) - pedwarn (loc, OPT_Wpedantic, + if (pedantic && cxx_dialect < cxx20) + pedwarn (loc, OPT_Wc__20_extensions, "C++ designated initializers only available with " "%<-std=c++20%> or %<-std=gnu++20%>"); /* Consume the `.'. */ @@ -25800,10 +25811,11 @@ cp_parser_type_parameter_key (cp_parser* parser) if ((tag_type = cp_parser_token_is_type_parameter_key (token)) != none_type) { cp_lexer_consume_token (parser->lexer); - if (pedantic && tag_type == typename_type && cxx_dialect < cxx17) + if (pedantic && tag_type == typename_type + && cxx_dialect < cxx17) /* typename is not allowed in a template template parameter by the standard until C++17. */ - pedwarn (token->location, OPT_Wpedantic, + pedwarn (token->location, OPT_Wc__17_extensions, "ISO C++ forbids typename key in template template parameter;" " use %<-std=c++17%> or %<-std=gnu++17%>"); } @@ -26197,7 +26209,7 @@ cp_parser_member_declaration (cp_parser* parser) = cp_lexer_peek_token (parser->lexer)->location; if (cxx_dialect < cxx20 && identifier != NULL_TREE) - pedwarn (loc, 0, + pedwarn (loc, OPT_Wc__20_extensions, "default member initializers for bit-fields " "only available with %<-std=c++20%> or " "%<-std=gnu++20%>"); @@ -27158,7 +27170,7 @@ cp_parser_try_block (cp_parser* parser) if (parser->in_function_body && DECL_DECLARED_CONSTEXPR_P (current_function_decl) && cxx_dialect < cxx20) - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__20_extensions, "% in % function only " "available with %<-std=c++20%> or %<-std=gnu++20%>"); @@ -28117,7 +28129,7 @@ cp_parser_std_attribute_spec (cp_parser *parser) && cp_lexer_nth_token_is (parser->lexer, 3, CPP_COLON)) { if (cxx_dialect < cxx17) - pedwarn (input_location, 0, + pedwarn (input_location, OPT_Wc__17_extensions, "attribute using prefix only available " "with %<-std=c++17%> or %<-std=gnu++17%>"); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index cbd2f3d..3d1787b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2703,7 +2703,7 @@ check_template_variable (tree decl) && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl))) { if (cxx_dialect < cxx14) - pedwarn (DECL_SOURCE_LOCATION (decl), 0, + pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__14_extensions, "variable templates only available with " "%<-std=c++14%> or %<-std=gnu++14%>"); -- cgit v1.1 From 84fd1b5dff70cd74aee7e8b18f66959d8b8e1ce7 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 19 May 2021 21:12:45 -0400 Subject: c++: designated init with anonymous union [PR100489] My patch for PR98463 added an assert that tripped on this testcase, because we ended up with a U CONSTRUCTOR with an initializer for a, which is not a member of U. We need to wrap the a initializer in another CONSTRUCTOR for the anonymous union. There was already support for this in process_init_constructor_record, but not in process_init_constructor_union. But since this is about brace elision, it really belongs under reshape_init rather than digest_init, so this patch moves the handling to reshape_init_class, which also handles unions. PR c++/100489 gcc/cp/ChangeLog: * decl.c (reshape_init_class): Handle designator for member of anonymous aggregate here. * typeck2.c (process_init_constructor_record): Not here. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/desig18.C: New test. --- gcc/cp/decl.c | 33 +++++++++++++++++++++++++++++---- gcc/cp/typeck2.c | 26 -------------------------- 2 files changed, 29 insertions(+), 30 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 7c32f09..6107b55 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6418,10 +6418,9 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p, /* We already reshaped this. */ if (field != d->cur->index) { - tree id = DECL_NAME (d->cur->index); - gcc_assert (id); - gcc_checking_assert (d->cur->index - == get_class_binding (type, id)); + if (tree id = DECL_NAME (d->cur->index)) + gcc_checking_assert (d->cur->index + == get_class_binding (type, id)); field = d->cur->index; } } @@ -6442,6 +6441,32 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p, d->cur->index); return error_mark_node; } + + /* If the element is an anonymous union object and the initializer + list is a designated-initializer-list, the anonymous union object + is initialized by the designated-initializer-list { D }, where D + is the designated-initializer-clause naming a member of the + anonymous union object. */ + tree ictx = DECL_CONTEXT (field); + if (!same_type_ignoring_top_level_qualifiers_p (ictx, type)) + { + gcc_assert (ANON_AGGR_TYPE_P (ictx)); + /* Find the anon aggr that is a direct member of TYPE. */ + while (true) + { + tree cctx = TYPE_CONTEXT (ictx); + if (same_type_ignoring_top_level_qualifiers_p (cctx, type)) + break; + ictx = cctx; + } + /* And then the TYPE member with that anon aggr type. */ + tree aafield = TYPE_FIELDS (type); + for (; aafield; aafield = TREE_CHAIN (aafield)) + if (TREE_TYPE (aafield) == ictx) + break; + gcc_assert (aafield); + field = aafield; + } } /* If we processed all the member of the class, we are done. */ diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index ce3016c..5a7219d 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1517,19 +1517,6 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, || identifier_p (ce->index)); if (ce->index == field || ce->index == DECL_NAME (field)) next = ce->value; - else if (ANON_AGGR_TYPE_P (fldtype) - && search_anon_aggr (fldtype, - TREE_CODE (ce->index) == FIELD_DECL - ? DECL_NAME (ce->index) - : ce->index)) - /* If the element is an anonymous union object and the - initializer list is a designated-initializer-list, the - anonymous union object is initialized by the - designated-initializer-list { D }, where D is the - designated-initializer-clause naming a member of the - anonymous union object. */ - next = build_constructor_single (init_list_type_node, - ce->index, ce->value); else { ce = NULL; @@ -1675,19 +1662,6 @@ process_init_constructor_record (tree type, tree init, int nested, int flags, if (ce->index == field || ce->index == DECL_NAME (field)) break; - if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) - { - tree t - = search_anon_aggr (TREE_TYPE (field), - TREE_CODE (ce->index) == FIELD_DECL - ? DECL_NAME (ce->index) - : ce->index); - if (t) - { - field = t; - break; - } - } } } if (field) -- cgit v1.1 From 885035eacb36b5bf1aa3b0d05f675ab89665d7be Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 19 May 2021 21:13:43 -0400 Subject: c++: designators in single-element init lists While looking at PR100489, it occurred to me that places that currently use an initializer-list with a single element to initialize an object of the same type shouldn't do that if the element has a designator. gcc/cp/ChangeLog: * call.c (reference_binding): Check for designator. (implicit_conversion_1, build_special_member_call): Likewise. * decl.c (reshape_init_r): Likewise. * pt.c (do_class_deduction): Likewise. * typeck2.c (digest_init_r): Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/desig19.C: New test. --- gcc/cp/call.c | 5 ++++- gcc/cp/decl.c | 2 ++ gcc/cp/pt.c | 3 ++- gcc/cp/typeck2.c | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index fa770f2..cfccf27 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -1731,7 +1731,8 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, because A[] and A[2] are reference-related. But we don't do it because grok_reference_init has deduced the array size (to 1), and A[1] and A[2] aren't reference-related. */ - if (CONSTRUCTOR_NELTS (expr) == 1) + if (CONSTRUCTOR_NELTS (expr) == 1 + && !CONSTRUCTOR_IS_DESIGNATED_INIT (expr)) { tree elt = CONSTRUCTOR_ELT (expr, 0)->value; if (error_operand_p (elt)) @@ -2095,6 +2096,7 @@ implicit_conversion_1 (tree to, tree from, tree expr, bool c_cast_p, { if (BRACE_ENCLOSED_INITIALIZER_P (expr) && CONSTRUCTOR_NELTS (expr) == 1 + && !CONSTRUCTOR_IS_DESIGNATED_INIT (expr) && !is_list_ctor (cand->fn)) { /* "If C is not an initializer-list constructor and the @@ -10199,6 +10201,7 @@ build_special_member_call (tree instance, tree name, vec **args, if (BRACE_ENCLOSED_INITIALIZER_P (arg) && !TYPE_HAS_LIST_CTOR (class_type) + && !CONSTRUCTOR_IS_DESIGNATED_INIT (arg) && CONSTRUCTOR_NELTS (arg) == 1) arg = CONSTRUCTOR_ELT (arg, 0)->value; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6107b55..e7268d5 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6650,6 +6650,8 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, initialized from that element." Even if T is an aggregate. */ if (cxx_dialect >= cxx11 && (CLASS_TYPE_P (type) || VECTOR_TYPE_P (type)) && first_initializer_p + /* But not if it's a designated init. */ + && !d->cur->index && d->end - d->cur == 1 && reference_related_p (type, TREE_TYPE (init))) { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3d1787b..99a9ee5 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -29326,7 +29326,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init, { list_init_p = true; try_list_ctor = TYPE_HAS_LIST_CTOR (type); - if (try_list_ctor && CONSTRUCTOR_NELTS (init) == 1) + if (try_list_ctor && CONSTRUCTOR_NELTS (init) == 1 + && !CONSTRUCTOR_IS_DESIGNATED_INIT (init)) { /* As an exception, the first phase in 16.3.1.7 (considering the initializer list as a single argument) is omitted if the diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 5a7219d..6679e24 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1183,6 +1183,7 @@ digest_init_r (tree type, tree init, int nested, int flags, the object is initialized from that element." */ if (cxx_dialect >= cxx11 && BRACE_ENCLOSED_INITIALIZER_P (stripped_init) + && !CONSTRUCTOR_IS_DESIGNATED_INIT (stripped_init) && CONSTRUCTOR_NELTS (stripped_init) == 1 && ((CLASS_TYPE_P (type) && !CLASSTYPE_NON_AGGREGATE (type)) || VECTOR_TYPE_P (type))) -- cgit v1.1 From ea34e2edd3d7ab245d1f57a1487c10587f324ec6 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 21 May 2021 00:16:57 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3f7cf15..d20edfb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,54 @@ +2021-05-20 Jason Merrill + + * call.c (reference_binding): Check for designator. + (implicit_conversion_1, build_special_member_call): Likewise. + * decl.c (reshape_init_r): Likewise. + * pt.c (do_class_deduction): Likewise. + * typeck2.c (digest_init_r): Likewise. + +2021-05-20 Jason Merrill + + PR c++/100489 + * decl.c (reshape_init_class): Handle designator for + member of anonymous aggregate here. + * typeck2.c (process_init_constructor_record): Not here. + +2021-05-20 Jonathan Wakely + + * call.c (maybe_warn_array_conv): Use new warning option. + * decl.c (mark_inline_variable, grokdeclarator): Likewise. + * error.c (maybe_warn_cpp0x): Likewise. + * parser.c (cp_parser_primary_expression) + (cp_parser_unqualified_id) + (cp_parser_pseudo_destructor_name) + (cp_parser_lambda_introducer) + (cp_parser_lambda_declarator_opt) + (cp_parser_selection_statement) + (cp_parser_init_statement) + (cp_parser_decomposition_declaration) + (cp_parser_function_specifier_opt) + (cp_parser_static_assert) + (cp_parser_namespace_definition) + (cp_parser_using_declaration) + (cp_parser_asm_definition) + (cp_parser_ctor_initializer_opt_and_function_body) + (cp_parser_initializer_list) + (cp_parser_type_parameter_key) + (cp_parser_member_declaration) + (cp_parser_try_block) + (cp_parser_std_attribute_spec): Likewise. + * pt.c (check_template_variable): Likewise. + +2021-05-20 Jason Merrill + + PR c++/100634 + * pt.c (invalid_nontype_parm_type_p): Return true for COMPLEX_TYPE. + +2021-05-20 Jason Merrill + + PR c++/100659 + * cp-tree.h (CONST_DECL_USING_P): Check for null TREE_TYPE. + 2021-05-19 Jason Merrill PR c++/100367 -- 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') 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 2832d51b383392e961373fb7067a73c6dfdc7cb1 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 22 May 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d20edfb..2eb793e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2021-05-21 Jakub Jelinek + + PR middle-end/99928 + * 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. + 2021-05-20 Jason Merrill * call.c (reference_binding): Check for designator. -- cgit v1.1 From ad52d89808a947264397e920d7483090d4108f7b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 25 May 2021 17:24:38 +0200 Subject: c++: Avoid -Wunused-value false positives on nullptr passed to ellipsis [PR100666] When passing expressions with decltype(nullptr) type with side-effects to ellipsis, we pass (void *)0 instead, but for the side-effects evaluate them on the lhs of a COMPOUND_EXPR. Unfortunately that means we warn about it if the expression is a call to nodiscard marked function, even when the result is really used, just needs to be transformed. Fixed by adding a warning_sentinel. 2021-05-25 Jakub Jelinek PR c++/100666 * call.c (convert_arg_to_ellipsis): For expressions with NULLPTR_TYPE and side-effects, temporarily disable -Wunused-result warning when building COMPOUND_EXPR. * g++.dg/cpp1z/nodiscard8.C: New test. * g++.dg/cpp1z/nodiscard9.C: New test. --- gcc/cp/call.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index cfccf27..3076fe6 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8178,7 +8178,10 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain) { arg = mark_rvalue_use (arg); if (TREE_SIDE_EFFECTS (arg)) - arg = cp_build_compound_expr (arg, null_pointer_node, complain); + { + warning_sentinel w(warn_unused_result); + arg = cp_build_compound_expr (arg, null_pointer_node, complain); + } else arg = null_pointer_node; } -- cgit v1.1 From 2bc6dacecb2ba60f1f06f310c6887a26b09cdba8 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 26 May 2021 00:16:41 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2eb793e..1cbd043 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2021-05-25 Jakub Jelinek + + PR c++/100666 + * call.c (convert_arg_to_ellipsis): For expressions with NULLPTR_TYPE + and side-effects, temporarily disable -Wunused-result warning when + building COMPOUND_EXPR. + 2021-05-21 Jakub Jelinek PR middle-end/99928 -- cgit v1.1 From b4329e3dd6fb7c78948fcf9d2f5b9d873deec284 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 26 May 2021 08:35:31 -0400 Subject: c++: Fix reference NTTP binding to noexcept fn [PR97420] Here, in C++17 mode, convert_nontype_argument_function is rejecting binding a non-noexcept function reference template parameter to a noexcept function (encoded as the template argument '*(int (&) (int)) &f'). The first roadblock to making this work is that the argument is wrapped an an implicit INDIRECT_REF, so we need to unwrap it before calling strip_fnptr_conv. The second roadblock is that the NOP_EXPR cast converts from a function pointer type to a reference type while simultaneously removing the noexcept qualification, and fnptr_conv_p doesn't consider this cast to be a function pointer conversion. This patch fixes this by making fnptr_conv_p treat REFERENCE_TYPEs and POINTER_TYPEs interchangeably. Finally, in passing, this patch also simplifies noexcept_conv_p by removing a bunch of redundant checks already performed by its only caller fnptr_conv_p. PR c++/97420 gcc/cp/ChangeLog: * cvt.c (noexcept_conv_p): Remove redundant checks and simplify. (fnptr_conv_p): Don't call non_reference. Use INDIRECT_TYPE_P instead of TYPE_PTR_P. * pt.c (convert_nontype_argument_function): Look through implicit INDIRECT_REFs before calling strip_fnptr_conv. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/noexcept68.C: New test. --- gcc/cp/cvt.c | 36 +++++++++++------------------------- gcc/cp/pt.c | 5 ++++- 2 files changed, 15 insertions(+), 26 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 7fa6e8d..330d658 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -2081,7 +2081,8 @@ can_convert_tx_safety (tree to, tree from) && same_type_p (to, tx_unsafe_fn_variant (from))); } -/* Return true iff FROM can convert to TO by dropping noexcept. */ +/* Return true iff FROM can convert to TO by dropping noexcept. + This is just a subroutine of of fnptr_conv_p. */ static bool noexcept_conv_p (tree to, tree from) @@ -2089,30 +2090,15 @@ noexcept_conv_p (tree to, tree from) if (!flag_noexcept_type) return false; - tree t = non_reference (to); - tree f = from; - if (TYPE_PTRMEMFUNC_P (t) - && TYPE_PTRMEMFUNC_P (f)) - { - t = TYPE_PTRMEMFUNC_FN_TYPE (t); - f = TYPE_PTRMEMFUNC_FN_TYPE (f); - } - if (TYPE_PTR_P (t) - && TYPE_PTR_P (f)) - { - t = TREE_TYPE (t); - f = TREE_TYPE (f); - } - tree_code code = TREE_CODE (f); - if (TREE_CODE (t) != code) + if (TREE_CODE (to) != TREE_CODE (from)) return false; - if (code != FUNCTION_TYPE && code != METHOD_TYPE) + if (!FUNC_OR_METHOD_TYPE_P (from)) return false; - if (!type_throw_all_p (t) - || type_throw_all_p (f)) + if (!type_throw_all_p (to) + || type_throw_all_p (from)) return false; - tree v = build_exception_variant (f, NULL_TREE); - return same_type_p (t, v); + tree v = build_exception_variant (from, NULL_TREE); + return same_type_p (to, v); } /* Return true iff FROM can convert to TO by a function pointer conversion. */ @@ -2120,7 +2106,7 @@ noexcept_conv_p (tree to, tree from) bool fnptr_conv_p (tree to, tree from) { - tree t = non_reference (to); + tree t = to; tree f = from; if (TYPE_PTRMEMFUNC_P (t) && TYPE_PTRMEMFUNC_P (f)) @@ -2128,8 +2114,8 @@ fnptr_conv_p (tree to, tree from) t = TYPE_PTRMEMFUNC_FN_TYPE (t); f = TYPE_PTRMEMFUNC_FN_TYPE (f); } - if (TYPE_PTR_P (t) - && TYPE_PTR_P (f)) + if (INDIRECT_TYPE_P (t) + && INDIRECT_TYPE_P (f)) { t = TREE_TYPE (t); f = TREE_TYPE (f); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 99a9ee5..f3fa9c1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6622,7 +6622,10 @@ convert_nontype_argument_function (tree type, tree expr, if (value_dependent_expression_p (fn)) goto accept; - fn_no_ptr = strip_fnptr_conv (fn); + fn_no_ptr = fn; + if (REFERENCE_REF_P (fn_no_ptr)) + fn_no_ptr = TREE_OPERAND (fn_no_ptr, 0); + fn_no_ptr = strip_fnptr_conv (fn_no_ptr); if (TREE_CODE (fn_no_ptr) == ADDR_EXPR) fn_no_ptr = TREE_OPERAND (fn_no_ptr, 0); if (BASELINK_P (fn_no_ptr)) -- cgit v1.1 From 88834c7d05acf5ce4eaccda56fb04436595e2a52 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 26 May 2021 08:37:30 -0400 Subject: c++: constexpr and copy elision within mem init [PR100368] In the testcase below, the member initializer b(f()) inside C's default constructor is encoded as a TARGET_EXPR wrapping the CALL_EXPR f() in C++17 mode. During massaging of this constexpr constructor, build_target_expr_with_type called from bot_manip on this initializer tries to add an extra copy using B's implicitly deleted copy constructor rather than just preserving the copy elision. Since it's wrong to introduce an extra copy when initializing a temporary from a CALL_EXPR, this patch makes build_target_expr_with_type avoid calling force_rvalue in this case. Additionally, bot_manip should be copying TARGET_EXPRs in a more oblivious manner, so this patch makes bot_manip use force_target_expr instead of build_target_expr_with_type. And since bot_manip is now no longer a caller, we can remove the void initializer handling in build_target_expr_with_type. PR c++/100368 gcc/cp/ChangeLog: * tree.c (build_target_expr_with_type): Don't call force_rvalue on CALL_EXPR initializer. Simplify now that bot_manip is no longer a caller. (bot_manip): Use force_target_expr instead of build_target_expr_with_type. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/elide6.C: New test. --- gcc/cp/tree.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 72f498f..372d89f 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -843,21 +843,22 @@ tree build_target_expr_with_type (tree init, tree type, tsubst_flags_t complain) { gcc_assert (!VOID_TYPE_P (type)); + gcc_assert (!VOID_TYPE_P (TREE_TYPE (init))); if (TREE_CODE (init) == TARGET_EXPR || init == error_mark_node) return init; else if (CLASS_TYPE_P (type) && type_has_nontrivial_copy_init (type) - && !VOID_TYPE_P (TREE_TYPE (init)) && TREE_CODE (init) != COND_EXPR && TREE_CODE (init) != CONSTRUCTOR - && TREE_CODE (init) != VA_ARG_EXPR) - /* We need to build up a copy constructor call. A void initializer - means we're being called from bot_manip. COND_EXPR is a special + && TREE_CODE (init) != VA_ARG_EXPR + && TREE_CODE (init) != CALL_EXPR) + /* We need to build up a copy constructor call. COND_EXPR is a special case because we already have copies on the arms and we don't want another one here. A CONSTRUCTOR is aggregate initialization, which is handled separately. A VA_ARG_EXPR is magic creation of an - aggregate; there's no additional work to be done. */ + aggregate; there's no additional work to be done. A CALL_EXPR + already creates a prvalue. */ return force_rvalue (init, complain); return force_target_expr (type, init, complain); @@ -3112,8 +3113,8 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_) AGGR_INIT_ZERO_FIRST (TREE_OPERAND (u, 1)) = true; } else - u = build_target_expr_with_type (TREE_OPERAND (t, 1), TREE_TYPE (t), - tf_warning_or_error); + u = force_target_expr (TREE_TYPE (t), TREE_OPERAND (t, 1), + tf_warning_or_error); TARGET_EXPR_IMPLICIT_P (u) = TARGET_EXPR_IMPLICIT_P (t); TARGET_EXPR_LIST_INIT_P (u) = TARGET_EXPR_LIST_INIT_P (t); -- cgit v1.1 From abe8787a8492013145b275b858f70943522d7226 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 26 May 2021 16:02:33 -0400 Subject: c++: access for hidden friend of nested class template [PR100502] Here, during ahead of time access checking for the private member EnumeratorRange::end_reached_ in the hidden friend f, we're triggering the assert in enforce_access that verifies we're not trying to add a access check for a dependent decl onto TI_DEFERRED_ACCESS_CHECKS. The special thing about this class member access expression is that the overall expression is non-dependent (so finish_class_member_access_expr doesn't exit early at parse time), and then accessible_p rejects the access (so we don't exit early from enforce access either, and end up triggering the assert b/c the member itself is dependent). I think we're correct to reject the access because a hidden friend is not a member function, so [class.access.nest] doesn't apply, and also a hidden friend of a nested class is not a friend of the enclosing class. To fix this ICE, this patch disables ahead of time access checking during the member lookup in finish_class_member_access_expr. This avoids potentially pushing an access check for a dependent member onto TI_DEFERRED_ACCESS_CHECKS, and it's safe because we're going to redo the same lookup at instantiation time anyway. PR c++/100502 gcc/cp/ChangeLog: * typeck.c (finish_class_member_access_expr): Disable ahead of time access checking during the member lookup. gcc/testsuite/ChangeLog: * g++.dg/template/access37.C: New test. * g++.dg/template/access37a.C: New test. --- gcc/cp/typeck.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 703ddd3..3df4117 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3201,9 +3201,19 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p, { /* Look up the member. */ access_failure_info afi; + if (processing_template_decl) + /* Even though this class member access expression is at this + point not dependent, the member itself may be dependent, and + we must not potentially push a access check for a dependent + member onto TI_DEFERRED_ACCESS_CHECKS. So don't check access + ahead of time here; we're going to redo this member lookup at + instantiation time anyway. */ + push_deferring_access_checks (dk_no_check); member = lookup_member (access_path, name, /*protect=*/1, /*want_type=*/false, complain, &afi); + if (processing_template_decl) + pop_deferring_access_checks (); afi.maybe_suggest_accessor (TYPE_READONLY (object_type)); if (member == NULL_TREE) { -- cgit v1.1 From 01c59ef2e5a59b44d2b662361196abb6be872a20 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 27 May 2021 00:16:53 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1cbd043..7c13a6e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,27 @@ +2021-05-26 Patrick Palka + + PR c++/100502 + * typeck.c (finish_class_member_access_expr): Disable ahead + of time access checking during the member lookup. + +2021-05-26 Patrick Palka + + PR c++/100368 + * tree.c (build_target_expr_with_type): Don't call force_rvalue + on CALL_EXPR initializer. Simplify now that bot_manip is no + longer a caller. + (bot_manip): Use force_target_expr instead of + build_target_expr_with_type. + +2021-05-26 Patrick Palka + + PR c++/97420 + * cvt.c (noexcept_conv_p): Remove redundant checks and simplify. + (fnptr_conv_p): Don't call non_reference. Use INDIRECT_TYPE_P + instead of TYPE_PTR_P. + * pt.c (convert_nontype_argument_function): Look through + implicit INDIRECT_REFs before calling strip_fnptr_conv. + 2021-05-25 Jakub Jelinek PR c++/100666 -- cgit v1.1 From 9b94785dedb08b006419bec1a402614d9241317a Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 27 May 2021 12:36:39 -0400 Subject: c++: Relax rule for non-type arguments in partial specs [CWG1315] This implements the wording changes of CWG 1315, which permits non-type template arguments in a partial specialization to use template parameters more freely. Delightfully, it seems the only change needed is to remove a single check from process_partial_specialization (amidst a bunch of whitespace changes). But that change alone revealed a latent problem with for_each_template_parm: it ends up looking into some non-deduced contexts even when include_nondeduced_p is false. This causes us to silently accept some partial specializations within the testsuite that contain non-deducible non-type template parameters (and that were previously rejected due to the rule that CWG 1315 relaxed). For now this patch makes a minimal amount of changes to for_each_template_parm_r so that we continue to reject existing ill-formed partial specializations within the testsuite. I opened PR c++/100779 to track this issue. DR 1315 PR c++/67593 PR c++/96555 gcc/cp/ChangeLog: * pt.c (process_partial_specialization): Don't error on a non-simple non-type template argument that involves template parameters. (for_each_template_parm_r): Don't walk TRAIT_EXPR, PLUS_EXPR, MULT_EXPR, or SCOPE_REF when include_nondeduced_p is false. gcc/testsuite/ChangeLog: * g++.dg/template/partial16.C: New test. * g++.dg/template/partial17.C: New test. * g++.dg/template/partial18.C: New test. * g++.dg/template/partial19.C: New test. * g++.dg/cpp0x/pr68724.C: Adjust expected diagnostic for ill-formed partial specialization. * g++.dg/cpp0x/variadic38.C: Likewise. * g++.dg/cpp1z/pr81016.C: Likewise. * g++.dg/template/partial5.C: Likewise. * g++.old-deja/g++.pt/spec21.C: Likewise. --- gcc/cp/pt.c | 122 ++++++++++++++++++++++++++++-------------------------------- 1 file changed, 57 insertions(+), 65 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f3fa9c1..e4950aa 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5157,11 +5157,7 @@ process_partial_specialization (tree decl) maintmpl); } - /* [temp.class.spec] - - A partially specialized non-type argument expression shall not - involve template parameters of the partial specialization except - when the argument expression is a simple identifier. + /* [temp.spec.partial] The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the @@ -5222,63 +5218,55 @@ process_partial_specialization (tree decl) || TREE_CODE (arg) == VIEW_CONVERT_EXPR) && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_PARM_INDEX)) { - if ((!packed_args && tpd.arg_uses_template_parms[i]) - || (packed_args && uses_template_parms (arg))) - error_at (cp_expr_loc_or_input_loc (arg), - "template argument %qE involves template " - "parameter(s)", arg); - else - { - /* Look at the corresponding template parameter, - marking which template parameters its type depends - upon. */ - tree type = TREE_TYPE (parm); + /* Look at the corresponding template parameter, + marking which template parameters its type depends + upon. */ + tree type = TREE_TYPE (parm); - if (!tpd2.parms) - { - /* We haven't yet initialized TPD2. Do so now. */ - tpd2.arg_uses_template_parms = XALLOCAVEC (int, nargs); - /* The number of parameters here is the number in the - main template, which, as checked in the assertion - above, is NARGS. */ - tpd2.parms = XALLOCAVEC (int, nargs); - tpd2.level = - TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl)); - } + if (!tpd2.parms) + { + /* We haven't yet initialized TPD2. Do so now. */ + tpd2.arg_uses_template_parms = XALLOCAVEC (int, nargs); + /* The number of parameters here is the number in the + main template, which, as checked in the assertion + above, is NARGS. */ + tpd2.parms = XALLOCAVEC (int, nargs); + tpd2.level = + TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl)); + } - /* Mark the template parameters. But this time, we're - looking for the template parameters of the main - template, not in the specialization. */ - tpd2.current_arg = i; - tpd2.arg_uses_template_parms[i] = 0; - memset (tpd2.parms, 0, sizeof (int) * nargs); - for_each_template_parm (type, - &mark_template_parm, - &tpd2, - NULL, - /*include_nondeduced_p=*/false); - - if (tpd2.arg_uses_template_parms [i]) - { - /* The type depended on some template parameters. - If they are fully specialized in the - specialization, that's OK. */ - int j; - int count = 0; - for (j = 0; j < nargs; ++j) - if (tpd2.parms[j] != 0 - && tpd.arg_uses_template_parms [j]) - ++count; - if (count != 0) - error_n (input_location, count, - "type %qT of template argument %qE depends " - "on a template parameter", - "type %qT of template argument %qE depends " - "on template parameters", - type, - arg); - } - } + /* Mark the template parameters. But this time, we're + looking for the template parameters of the main + template, not in the specialization. */ + tpd2.current_arg = i; + tpd2.arg_uses_template_parms[i] = 0; + memset (tpd2.parms, 0, sizeof (int) * nargs); + for_each_template_parm (type, + &mark_template_parm, + &tpd2, + NULL, + /*include_nondeduced_p=*/false); + + if (tpd2.arg_uses_template_parms [i]) + { + /* The type depended on some template parameters. + If they are fully specialized in the + specialization, that's OK. */ + int j; + int count = 0; + for (j = 0; j < nargs; ++j) + if (tpd2.parms[j] != 0 + && tpd.arg_uses_template_parms [j]) + ++count; + if (count != 0) + error_n (input_location, count, + "type %qT of template argument %qE depends " + "on a template parameter", + "type %qT of template argument %qE depends " + "on template parameters", + type, + arg); + } } } } @@ -10502,6 +10490,15 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) return error_mark_node; break; + case TRAIT_EXPR: + case PLUS_EXPR: + case MULT_EXPR: + case SCOPE_REF: + /* These are non-deduced contexts. */ + if (!pfd->include_nondeduced_p) + *walk_subtrees = 0; + break; + case MODOP_EXPR: case CAST_EXPR: case IMPLICIT_CONV_EXPR: @@ -10517,11 +10514,6 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) return error_mark_node; break; - case SCOPE_REF: - if (pfd->include_nondeduced_p) - WALK_SUBTREE (TREE_OPERAND (t, 0)); - break; - case REQUIRES_EXPR: { if (!fn) -- cgit v1.1 From db79713150f4f8b6ff3de81d00d92578679e0e65 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 26 May 2021 17:38:42 -0400 Subject: c++: argument pack with expansion [PR86355] This testcase revealed that we were using PACK_EXPANSION_EXTRA_ARGS a lot more than necessary; use_pack_expansion_extra_args_p meant to use it in the case of corresponding arguments in different argument packs differing in whether they are pack expansions, but it was mistakenly also returning true for the case of a single argument pack containing both expansion and non-expansion elements. Surprisingly, just disabling that didn't lead to any regressions in the testsuite; it seems other changes have prevented us getting to this point for code that used to exercise it. So this patch limits the check to arguments in the same position in the packs, and asserts that we never actually see a mismatch. PR c++/86355 gcc/cp/ChangeLog: * pt.c (use_pack_expansion_extra_args_p): Don't compare args from the same argument pack. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/alias-decl-variadic2.C: New test. --- gcc/cp/pt.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index e4950aa..bb22d68 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12422,9 +12422,9 @@ use_pack_expansion_extra_args_p (tree parm_packs, return false; } - bool has_expansion_arg = false; for (int i = 0 ; i < arg_pack_len; ++i) { + bool has_expansion_arg = false; bool has_non_expansion_arg = false; for (tree parm_pack = parm_packs; parm_pack; @@ -12444,7 +12444,10 @@ use_pack_expansion_extra_args_p (tree parm_packs, } if (has_expansion_arg && has_non_expansion_arg) - return true; + { + gcc_checking_assert (false); + return true; + } } return false; } -- cgit v1.1 From fc3fdf0f2196e805a3a43ccb73595c33673670f3 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 27 May 2021 14:25:33 -0400 Subject: c++: parameter pack inside static_assert [PR99893] Here, we're not finding the parameter pack inside the static_assert because STATIC_ASSERT trees are tcc_exceptional, and we weren't explicitly walking them in cp_walk_subtrees. PR c++/99893 gcc/cp/ChangeLog: * tree.c (cp_walk_subtrees) : New case. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/static_assert17.C: New test. --- gcc/cp/tree.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 372d89f..fec5afa 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -5446,6 +5446,11 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, } break; + case STATIC_ASSERT: + WALK_SUBTREE (STATIC_ASSERT_CONDITION (*tp)); + WALK_SUBTREE (STATIC_ASSERT_MESSAGE (*tp)); + break; + default: return NULL_TREE; } -- cgit v1.1 From 27e906d5bb2e46e59fe4aa137317f3c8d49ecb44 Mon Sep 17 00:00:00 2001 From: Matthias Kretz Date: Thu, 27 May 2021 17:30:34 +0200 Subject: c++: Add missing scope in typedef diagnostic [PR100763] dump_type on 'const std::string' should not print 'const string' unless TFF_UNQUALIFIED_NAME is requested. gcc/cp/ChangeLog: PR c++/100763 * error.c: Call dump_scope when printing a typedef. --- gcc/cp/error.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 3d5eebd..ae78b10 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -501,6 +501,8 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) else { pp_cxx_cv_qualifier_seq (pp, t); + if (! (flags & TFF_UNQUALIFIED_NAME)) + dump_scope (pp, CP_DECL_CONTEXT (decl), flags); pp_cxx_tree_identifier (pp, TYPE_IDENTIFIER (t)); return; } -- cgit v1.1 From c33ec196aa713c62d73907dc8f9e57d7ab2e4e4b Mon Sep 17 00:00:00 2001 From: Matthias Kretz Date: Thu, 27 May 2021 17:25:37 +0200 Subject: c++: Output less irrelevant info for function template decl [PR100716] Ensure dump_template_decl for function templates never prints template parameters after the function name (it did with -fno-pretty-templates) and skip output of irrelevant & confusing "[with T = T]" in dump_substitution. gcc/cp/ChangeLog: PR c++/100716 * error.c (dump_template_bindings): Include code to print "[with" and ']', conditional on whether anything is printed at all. This is tied to whether a semicolon is needed to separate multiple template parameters. If the template argument repeats the template parameter (T = T), then skip the parameter. (dump_substitution): Moved code to print "[with" and ']' to dump_template_bindings. (dump_function_decl): Partial revert of PR50828, which masked TFF_TEMPLATE_NAME for all of dump_function_decl. Now TFF_TEMPLATE_NAME is masked for the scope of the function and only carries through to dump_function_name. (dump_function_name): Avoid calling dump_template_parms if TFF_TEMPLATE_NAME is set. gcc/testsuite/ChangeLog: PR c++/100716 * g++.dg/diagnostic/pr100716.C: New test. * g++.dg/diagnostic/pr100716-1.C: Same test with -fno-pretty-templates. --- gcc/cp/error.c | 63 ++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 15 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/error.c b/gcc/cp/error.c index ae78b10..4a89b34 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -371,7 +371,35 @@ static void dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args, vec *typenames) { - bool need_semicolon = false; + /* Print "[with" and ']', conditional on whether anything is printed at all. + This is tied to whether a semicolon is needed to separate multiple template + parameters. */ + struct prepost_semicolon + { + cxx_pretty_printer *pp; + bool need_semicolon; + + void operator() () + { + if (need_semicolon) + pp_separate_with_semicolon (pp); + else + { + pp_cxx_whitespace (pp); + pp_cxx_left_bracket (pp); + pp->translate_string ("with"); + pp_cxx_whitespace (pp); + need_semicolon = true; + } + } + + ~prepost_semicolon () + { + if (need_semicolon) + pp_cxx_right_bracket (pp); + } + } semicolon_or_introducer = {pp, false}; + int i; tree t; @@ -395,10 +423,20 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args, if (lvl_args && NUM_TMPL_ARGS (lvl_args) > arg_idx) arg = TREE_VEC_ELT (lvl_args, arg_idx); - if (need_semicolon) - pp_separate_with_semicolon (pp); - dump_template_parameter (pp, TREE_VEC_ELT (p, i), - TFF_PLAIN_IDENTIFIER); + tree parm_i = TREE_VEC_ELT (p, i); + /* If the template argument repeats the template parameter (T = T), + skip the parameter.*/ + if (arg && TREE_CODE (arg) == TEMPLATE_TYPE_PARM + && TREE_CODE (parm_i) == TREE_LIST + && TREE_CODE (TREE_VALUE (parm_i)) == TYPE_DECL + && TREE_CODE (TREE_TYPE (TREE_VALUE (parm_i))) + == TEMPLATE_TYPE_PARM + && DECL_NAME (TREE_VALUE (parm_i)) + == DECL_NAME (TREE_CHAIN (arg))) + continue; + + semicolon_or_introducer (); + dump_template_parameter (pp, parm_i, TFF_PLAIN_IDENTIFIER); pp_cxx_whitespace (pp); pp_equal (pp); pp_cxx_whitespace (pp); @@ -414,7 +452,6 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args, pp_string (pp, M_("")); ++arg_idx; - need_semicolon = true; } parms = TREE_CHAIN (parms); @@ -436,8 +473,7 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args, FOR_EACH_VEC_SAFE_ELT (typenames, i, t) { - if (need_semicolon) - pp_separate_with_semicolon (pp); + semicolon_or_introducer (); dump_type (pp, t, TFF_PLAIN_IDENTIFIER); pp_cxx_whitespace (pp); pp_equal (pp); @@ -1599,12 +1635,7 @@ dump_substitution (cxx_pretty_printer *pp, && !(flags & TFF_NO_TEMPLATE_BINDINGS)) { vec *typenames = t ? find_typenames (t) : NULL; - pp_cxx_whitespace (pp); - pp_cxx_left_bracket (pp); - pp->translate_string ("with"); - pp_cxx_whitespace (pp); dump_template_bindings (pp, template_parms, template_args, typenames); - pp_cxx_right_bracket (pp); } } @@ -1645,7 +1676,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) bool constexpr_p; tree ret = NULL_TREE; - flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME); + int dump_function_name_flags = flags & ~TFF_UNQUALIFIED_NAME; + flags = dump_function_name_flags & ~TFF_TEMPLATE_NAME; if (TREE_CODE (t) == TEMPLATE_DECL) t = DECL_TEMPLATE_RESULT (t); @@ -1723,7 +1755,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) else dump_scope (pp, CP_DECL_CONTEXT (t), flags); - dump_function_name (pp, t, flags); + dump_function_name (pp, t, dump_function_name_flags); if (!(flags & TFF_NO_FUNCTION_ARGUMENTS)) { @@ -1937,6 +1969,7 @@ dump_function_name (cxx_pretty_printer *pp, tree t, int flags) dump_module_suffix (pp, t); if (DECL_TEMPLATE_INFO (t) + && !(flags & TFF_TEMPLATE_NAME) && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (t) && (TREE_CODE (DECL_TI_TEMPLATE (t)) != TEMPLATE_DECL || PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t)))) -- cgit v1.1 From cd62d089f6021fd1ad4537b8182836d15b14514f Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 28 May 2021 00:16:38 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7c13a6e..d4aa545 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,47 @@ +2021-05-27 Matthias Kretz + + PR c++/100716 + * error.c (dump_template_bindings): Include code to print + "[with" and ']', conditional on whether anything is printed at + all. This is tied to whether a semicolon is needed to separate + multiple template parameters. If the template argument repeats + the template parameter (T = T), then skip the parameter. + (dump_substitution): Moved code to print "[with" and ']' to + dump_template_bindings. + (dump_function_decl): Partial revert of PR50828, which masked + TFF_TEMPLATE_NAME for all of dump_function_decl. Now + TFF_TEMPLATE_NAME is masked for the scope of the function and + only carries through to dump_function_name. + (dump_function_name): Avoid calling dump_template_parms if + TFF_TEMPLATE_NAME is set. + +2021-05-27 Matthias Kretz + + PR c++/100763 + * error.c: Call dump_scope when printing a typedef. + +2021-05-27 Patrick Palka + + PR c++/99893 + * tree.c (cp_walk_subtrees) : New case. + +2021-05-27 Jason Merrill + + PR c++/86355 + * pt.c (use_pack_expansion_extra_args_p): Don't compare + args from the same argument pack. + +2021-05-27 Patrick Palka + + DR 1315 + PR c++/67593 + PR c++/96555 + * pt.c (process_partial_specialization): Don't error on a + non-simple non-type template argument that involves template + parameters. + (for_each_template_parm_r): Don't walk TRAIT_EXPR, PLUS_EXPR, + MULT_EXPR, or SCOPE_REF when include_nondeduced_p is false. + 2021-05-26 Patrick Palka PR c++/100502 -- 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/parser.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++------ gcc/cp/semantics.c | 53 ++++++++++++++++++++++----------- 2 files changed, 113 insertions(+), 26 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 48b83d6..84c6be8 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -35117,7 +35117,9 @@ cp_parser_omp_clause_name (cp_parser *parser) switch (p[0]) { case 'a': - if (!strcmp ("aligned", p)) + if (!strcmp ("affinity", p)) + result = PRAGMA_OMP_CLAUSE_AFFINITY; + else if (!strcmp ("aligned", p)) result = PRAGMA_OMP_CLAUSE_ALIGNED; else if (!strcmp ("allocate", p)) result = PRAGMA_OMP_CLAUSE_ALLOCATE; @@ -35376,7 +35378,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, { tree name, decl; - if (kind == OMP_CLAUSE_DEPEND) + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) cp_parser_parse_tentatively (parser); token = cp_lexer_peek_token (parser->lexer); if (kind != 0 @@ -35405,7 +35407,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, /*optional_p=*/false); if (name == error_mark_node) { - if (kind == OMP_CLAUSE_DEPEND + if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) && cp_parser_simulate_error (parser)) goto depend_lvalue; goto skip_comma; @@ -35417,7 +35419,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, decl = name; if (decl == error_mark_node) { - if (kind == OMP_CLAUSE_DEPEND + if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) && cp_parser_simulate_error (parser)) goto depend_lvalue; cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, @@ -35463,6 +35465,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, &idk, loc); } /* FALLTHROUGH. */ + case OMP_CLAUSE_AFFINITY: case OMP_CLAUSE_DEPEND: case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_IN_REDUCTION: @@ -35489,12 +35492,12 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, /* Look for `:'. */ if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) { - if (kind == OMP_CLAUSE_DEPEND + if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) && cp_parser_simulate_error (parser)) goto depend_lvalue; goto skip_comma; } - if (kind == OMP_CLAUSE_DEPEND) + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) cp_parser_commit_to_tentative_parse (parser); if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) @@ -35508,7 +35511,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)) { - if (kind == OMP_CLAUSE_DEPEND + if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) && cp_parser_simulate_error (parser)) goto depend_lvalue; goto skip_comma; @@ -35521,7 +35524,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, break; } - if (kind == OMP_CLAUSE_DEPEND) + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) { if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA) && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN) @@ -37761,6 +37764,66 @@ cp_parser_omp_iterators (cp_parser *parser) return ret ? ret : error_mark_node; } +/* OpenMP 5.0: + affinity ( [aff-modifier :] variable-list ) + aff-modifier: + iterator ( iterators-definition ) */ + +static tree +cp_parser_omp_clause_affinity (cp_parser *parser, tree list) +{ + tree nlist, c, iterators = NULL_TREE; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + bool parse_iter = ((strcmp ("iterator", p) == 0) + && (cp_lexer_nth_token_is (parser->lexer, 2, + CPP_OPEN_PAREN))); + if (parse_iter) + { + size_t n = cp_parser_skip_balanced_tokens (parser, 2); + parse_iter = cp_lexer_nth_token_is (parser->lexer, n, CPP_COLON); + } + if (parse_iter) + { + begin_scope (sk_omp, NULL); + iterators = cp_parser_omp_iterators (parser); + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + { + if (iterators) + poplevel (0, 1, 0); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + } + } + nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_AFFINITY, + list, NULL); + if (iterators) + { + tree block = poplevel (1, 1, 0); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + { + TREE_VEC_ELT (iterators, 5) = block; + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_DECL (c) = build_tree_list (iterators, + OMP_CLAUSE_DECL (c)); + } + } + return nlist; +} + /* OpenMP 4.0: depend ( depend-kind : variable-list ) @@ -38753,6 +38816,10 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, } c_name = "linear"; break; + case PRAGMA_OMP_CLAUSE_AFFINITY: + clauses = cp_parser_omp_clause_affinity (parser, clauses); + c_name = "affinity"; + break; case PRAGMA_OMP_CLAUSE_DEPEND: clauses = cp_parser_omp_clause_depend (parser, clauses, token->location); @@ -41349,7 +41416,8 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok, bool *if_p) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_AFFINITY)) static tree cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok, bool *if_p) 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') 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 f838e3ccf8d2849980e9d0f70aa60ecd2eb5772c Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 27 May 2021 23:54:52 -0400 Subject: c++: 'this' adjustment for devirtualized call My patch for 95719 made us do a better job of finding the actual virtual function we want to call, but didn't update the 'this' pointer adjustment to match. PR c++/100797 PR c++/95719 gcc/cp/ChangeLog: * call.c (build_over_call): Adjust base_binfo in resolves_to_fixed_type_p case. gcc/testsuite/ChangeLog: * g++.dg/inherit/virtual15.C: New test. --- gcc/cp/call.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 3076fe6..bf524b5 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9152,18 +9152,32 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) if (base_binfo == error_mark_node) return error_mark_node; } - tree converted_arg = build_base_path (PLUS_EXPR, arg, - base_binfo, 1, complain); /* If we know the dynamic type of the object, look up the final overrider in the BINFO. */ if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0 && resolves_to_fixed_type_p (arg)) { - fn = lookup_vfn_in_binfo (DECL_VINDEX (fn), base_binfo); - flags |= LOOKUP_NONVIRTUAL; + tree ov = lookup_vfn_in_binfo (DECL_VINDEX (fn), base_binfo); + + /* And unwind base_binfo to match. If we don't find the type we're + looking for in BINFO_INHERITANCE_CHAIN, we're looking at diamond + inheritance; for now do a normal virtual call in that case. */ + tree octx = DECL_CONTEXT (ov); + tree obinfo = base_binfo; + while (obinfo && !SAME_BINFO_TYPE_P (BINFO_TYPE (obinfo), octx)) + obinfo = BINFO_INHERITANCE_CHAIN (obinfo); + if (obinfo) + { + fn = ov; + base_binfo = obinfo; + flags |= LOOKUP_NONVIRTUAL; + } } + tree converted_arg = build_base_path (PLUS_EXPR, arg, + base_binfo, 1, complain); + argarray[j++] = converted_arg; parm = TREE_CHAIN (parm); if (first_arg != NULL_TREE) -- 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/constexpr.c | 42 ++++++++++++++---------------------------- gcc/cp/coroutines.cc | 10 ++++------ gcc/cp/module.cc | 5 ++--- gcc/cp/pt.c | 5 ++--- gcc/cp/semantics.c | 5 ++--- 5 files changed, 24 insertions(+), 43 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 9cb761d..297f207 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -330,12 +330,9 @@ build_data_member_initialization (tree t, vec **vec) return false; if (TREE_CODE (t) == STATEMENT_LIST) { - tree_stmt_iterator i; - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) - { - if (! build_data_member_initialization (tsi_stmt (i), vec)) - return false; - } + for (tree stmt : tsi_range (t)) + if (! build_data_member_initialization (stmt, vec)) + return false; return true; } if (TREE_CODE (t) == CLEANUP_STMT) @@ -577,10 +574,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body) break; case STATEMENT_LIST: - for (tree_stmt_iterator i = tsi_start (body); - !tsi_end_p (i); tsi_next (&i)) + for (tree stmt : tsi_range (body)) { - body = tsi_stmt (i); + body = stmt; if (TREE_CODE (body) == BIND_EXPR) break; } @@ -617,10 +613,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body) } else if (TREE_CODE (body) == STATEMENT_LIST) { - tree_stmt_iterator i; - for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i)) + for (tree stmt : tsi_range (body)) { - ok = build_data_member_initialization (tsi_stmt (i), &vec); + ok = build_data_member_initialization (stmt, &vec); if (!ok) break; } @@ -675,11 +670,10 @@ constexpr_fn_retval (tree body) { case STATEMENT_LIST: { - tree_stmt_iterator i; tree expr = NULL_TREE; - for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i)) + for (tree stmt : tsi_range (body)) { - tree s = constexpr_fn_retval (tsi_stmt (i)); + tree s = constexpr_fn_retval (stmt); if (s == error_mark_node) return error_mark_node; else if (s == NULL_TREE) @@ -5772,7 +5766,6 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { - tree_stmt_iterator i; tree local_target; /* In a statement-expression we want to return the last value. For empty statement expression return void_node. */ @@ -5782,9 +5775,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, local_target = NULL_TREE; jump_target = &local_target; } - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) + for (tree stmt : tsi_range (t)) { - tree stmt = tsi_stmt (i); /* We've found a continue, so skip everything until we reach the label its jumping to. */ if (continues (jump_target)) @@ -8282,16 +8274,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, } case STATEMENT_LIST: - { - tree_stmt_iterator i; - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) - { - if (!RECUR (tsi_stmt (i), any)) - return false; - } - return true; - } - break; + for (tree stmt : tsi_range (t)) + if (!RECUR (stmt, any)) + return false; + return true; case MODIFY_EXPR: if (cxx_dialect < cxx14) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 7166206..1bf1931 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1764,10 +1764,9 @@ await_statement_expander (tree *stmt, int *do_subtree, void *d) return NULL_TREE; /* Just process the sub-trees. */ else if (TREE_CODE (*stmt) == STATEMENT_LIST) { - tree_stmt_iterator i; - for (i = tsi_start (*stmt); !tsi_end_p (i); tsi_next (&i)) + for (tree &s : tsi_range (*stmt)) { - res = cp_walk_tree (tsi_stmt_ptr (i), await_statement_expander, + res = cp_walk_tree (&s, await_statement_expander, d, NULL); if (res) return res; @@ -3509,10 +3508,9 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) } else if (TREE_CODE (*stmt) == STATEMENT_LIST) { - tree_stmt_iterator i; - for (i = tsi_start (*stmt); !tsi_end_p (i); tsi_next (&i)) + for (tree &s : tsi_range (*stmt)) { - res = cp_walk_tree (tsi_stmt_ptr (i), await_statement_walker, + res = cp_walk_tree (&s, await_statement_walker, d, NULL); if (res) return res; diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 02c19f5..f0fb014 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -6094,9 +6094,8 @@ trees_out::core_vals (tree t) break; case STATEMENT_LIST: - for (tree_stmt_iterator iter = tsi_start (t); - !tsi_end_p (iter); tsi_next (&iter)) - if (tree stmt = tsi_stmt (iter)) + for (tree stmt : tsi_range (t)) + if (stmt) WT (stmt); WT (NULL_TREE); break; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index bb22d68..b476ca8 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -18152,9 +18152,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, { case STATEMENT_LIST: { - tree_stmt_iterator i; - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) - RECUR (tsi_stmt (i)); + for (tree stmt : tsi_range (t)) + RECUR (stmt); break; } 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 48166757dcf46d92cf1795dd7333dda7030179c8 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 29 May 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d4aa545..882c8eb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,44 @@ +2021-05-28 Jason Merrill + + * 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. + +2021-05-28 Jason Merrill + + PR c++/100797 + PR c++/95719 + * call.c (build_over_call): Adjust base_binfo in + resolves_to_fixed_type_p case. + +2021-05-28 Jakub Jelinek + + PR middle-end/99928 + * 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. + +2021-05-28 Tobias Burnus + + * 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. + 2021-05-27 Matthias Kretz PR c++/100716 -- cgit v1.1 From ef8176e0fac935c095cc39f4ecdfd43cdb8cb3f3 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 21 May 2021 11:33:30 +0200 Subject: c++/88601 - [C/C++] __builtin_shufflevector support This adds support for the clang __builtin_shufflevector extension to the C and C++ frontends. The builtin is lowered to VEC_PERM_EXPR. Because VEC_PERM_EXPR does not support different sized vector inputs or result or the special permute index of -1 (don't-care) c_build_shufflevector applies lowering by widening inputs and output to the widest vector, replacing -1 by a defined index and subsetting the final vector if we produced a wider result than desired. Code generation thus can be sub-optimal, followup patches will aim to fix that by recovering from part of the missing features during RTL expansion and by relaxing the constraints of the GIMPLE IL with regard to VEC_PERM_EXPR. 2021-05-21 Richard Biener PR c++/88601 gcc/c-family/ * c-common.c: Include tree-vector-builder.h and vec-perm-indices.h. (c_common_reswords): Add __builtin_shufflevector. (c_build_shufflevector): New funtion. * c-common.h (enum rid): Add RID_BUILTIN_SHUFFLEVECTOR. (c_build_shufflevector): Declare. gcc/c/ * c-decl.c (names_builtin_p): Handle RID_BUILTIN_SHUFFLEVECTOR. * c-parser.c (c_parser_postfix_expression): Likewise. gcc/cp/ * cp-objcp-common.c (names_builtin_p): Handle RID_BUILTIN_SHUFFLEVECTOR. * cp-tree.h (build_x_shufflevector): Declare. * parser.c (cp_parser_postfix_expression): Handle RID_BUILTIN_SHUFFLEVECTOR. * pt.c (tsubst_copy_and_build): Handle IFN_SHUFFLEVECTOR. * typeck.c (build_x_shufflevector): Build either a lowered VEC_PERM_EXPR or an unlowered shufflevector via a temporary internal function IFN_SHUFFLEVECTOR. gcc/ * internal-fn.c (expand_SHUFFLEVECTOR): Define. * internal-fn.def (SHUFFLEVECTOR): New. * internal-fn.h (expand_SHUFFLEVECTOR): Declare. * doc/extend.texi: Document __builtin_shufflevector. gcc/testsuite/ * c-c++-common/builtin-shufflevector-2.c: New testcase. * c-c++-common/torture/builtin-shufflevector-1.c: Likewise. * g++.dg/ext/builtin-shufflevector-1.C: Likewise. * g++.dg/ext/builtin-shufflevector-2.C: Likewise. --- gcc/cp/cp-objcp-common.c | 1 + gcc/cp/cp-tree.h | 3 +++ gcc/cp/parser.c | 15 +++++++++++++++ gcc/cp/pt.c | 9 +++++++++ gcc/cp/typeck.c | 36 ++++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 9847270..46b2248 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -390,6 +390,7 @@ names_builtin_p (const char *name) case RID_BUILTIN_CONVERTVECTOR: case RID_BUILTIN_HAS_ATTRIBUTE: case RID_BUILTIN_SHUFFLE: + case RID_BUILTIN_SHUFFLEVECTOR: case RID_BUILTIN_LAUNDER: case RID_BUILTIN_BIT_CAST: case RID_OFFSETOF: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index aa20271..c95a820 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7895,6 +7895,9 @@ extern tree cp_build_binary_op (const op_location_t &, extern tree build_x_vec_perm_expr (location_t, tree, tree, tree, tsubst_flags_t); +extern tree build_x_shufflevector (location_t, + vec *, + tsubst_flags_t); #define cxx_sizeof(T) cxx_sizeof_or_alignof_type (input_location, T, SIZEOF_EXPR, false, true) extern tree build_simple_component_ref (tree, tree); extern tree build_ptrmemfunc_access_expr (tree, tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 84c6be8..4a46828 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7295,6 +7295,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, case RID_ADDRESSOF: case RID_BUILTIN_SHUFFLE: + case RID_BUILTIN_SHUFFLEVECTOR: case RID_BUILTIN_LAUNDER: { vec *vec; @@ -7357,6 +7358,20 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, } break; + case RID_BUILTIN_SHUFFLEVECTOR: + if (vec->length () < 3) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_shufflevector%>"); + postfix_expression = error_mark_node; + } + else + { + postfix_expression + = build_x_shufflevector (loc, vec, tf_warning_or_error); + } + break; + default: gcc_unreachable (); } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b476ca8..3130280 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20397,6 +20397,15 @@ tsubst_copy_and_build (tree t, RETURN (ret); break; + case IFN_SHUFFLEVECTOR: + { + ret = build_x_shufflevector (input_location, call_args, + complain); + if (ret != error_mark_node) + RETURN (ret); + break; + } + default: /* Unsupported internal function with arguments. */ gcc_unreachable (); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 3df4117..dbb2370 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5989,6 +5989,42 @@ build_x_vec_perm_expr (location_t loc, orig_arg1, orig_arg2); return exp; } + +/* Build a VEC_PERM_EXPR. + This is a simple wrapper for c_build_shufflevector. */ +tree +build_x_shufflevector (location_t loc, vec *args, + tsubst_flags_t complain) +{ + tree arg0 = (*args)[0]; + tree arg1 = (*args)[1]; + if (processing_template_decl) + { + for (unsigned i = 0; i < args->length (); ++i) + if (type_dependent_expression_p ((*args)[i])) + { + tree exp = build_min_nt_call_vec (NULL, args); + CALL_EXPR_IFN (exp) = IFN_SHUFFLEVECTOR; + return exp; + } + arg0 = build_non_dependent_expr (arg0); + arg1 = build_non_dependent_expr (arg1); + /* ??? Nothing needed for the index arguments? */ + } + auto_vec mask; + for (unsigned i = 2; i < args->length (); ++i) + { + tree idx = maybe_constant_value ((*args)[i]); + mask.safe_push (idx); + } + tree exp = c_build_shufflevector (loc, arg0, arg1, mask, complain & tf_error); + if (processing_template_decl && exp != error_mark_node) + { + exp = build_min_non_dep_call_vec (exp, NULL, args); + CALL_EXPR_IFN (exp) = IFN_SHUFFLEVECTOR; + } + return exp; +} /* Return a tree for the sum or difference (RESULTCODE says which) of pointer PTROP and integer INTOP. */ -- cgit v1.1 From ee682192755bb88af0ee10852e7c873b844d449f Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 1 Jun 2021 00:16:37 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 882c8eb..c764713 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2021-05-31 Richard Biener + + PR c++/88601 + * cp-objcp-common.c (names_builtin_p): Handle + RID_BUILTIN_SHUFFLEVECTOR. + * cp-tree.h (build_x_shufflevector): Declare. + * parser.c (cp_parser_postfix_expression): Handle + RID_BUILTIN_SHUFFLEVECTOR. + * pt.c (tsubst_copy_and_build): Handle IFN_SHUFFLEVECTOR. + * typeck.c (build_x_shufflevector): Build either a lowered + VEC_PERM_EXPR or an unlowered shufflevector via a temporary + internal function IFN_SHUFFLEVECTOR. + 2021-05-28 Jason Merrill * constexpr.c (build_data_member_initialization): Use tsi_range. -- cgit v1.1 From 620cd7861e1266991c9c2a82e1e2d5f4d723ec88 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 27 Apr 2021 17:13:39 -0400 Subject: c++: -Wdeprecated-copy and #pragma diagnostic [PR94492] -Wdeprecated-copy was depending only on the state of the warning at the point where we call the function, making it hard to use #pragma diagnostic to suppress the warning for a particular implicitly declared function. But checking whether the warning is enabled at the location of the implicit declaration turned out to be a bit complicated; option_enabled only tests whether it was enabled at the start of compilation, the actual test only existed in the middle of diagnostic_report_diagnostic. So this patch factors it out and adds a new warning_enabled function to diagnostic.h. gcc/ChangeLog: PR c++/94492 * diagnostic.h (warning_enabled_at): Declare. * diagnostic.c (diagnostic_enabled): Factor out from... (diagnostic_report_diagnostic): ...here. (warning_enabled_at): New. gcc/cp/ChangeLog: PR c++/94492 * decl2.c (cp_warn_deprecated_use): Check warning_enabled_at. gcc/testsuite/ChangeLog: PR c++/94492 * g++.dg/cpp0x/depr-copy4.C: New test. --- gcc/cp/decl2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 89f874a..e46fded 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -5499,10 +5499,10 @@ cp_warn_deprecated_use (tree decl, tsubst_flags_t complain) && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl) && copy_fn_p (decl)) { - if (warn_deprecated_copy - /* Don't warn about system library classes (c++/86342). */ - && (!DECL_IN_SYSTEM_HEADER (decl) - || global_dc->dc_warn_system_headers)) + /* Don't warn if the flag was disabled around the class definition + (c++/94492). */ + if (warning_enabled_at (DECL_SOURCE_LOCATION (decl), + OPT_Wdeprecated_copy)) { auto_diagnostic_group d; tree ctx = DECL_CONTEXT (decl); -- cgit v1.1 From cf2b7020ee8e9745ede527b0a3b2e0ffbafd492b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 28 May 2021 17:05:23 -0400 Subject: c++: no clobber for C++20 destroying delete [PR91859] Before C++20 added destroying operator delete, by the time we called operator delete for a pointer, the object would already be gone. But that isn't true for destroying delete. Since the optimizers' assumptions about operator delete are based on either DECL_IS_REPLACEABLE_OPERATOR (which already is not set) or CALL_FROM_NEW_OR_DELETE_P, let's avoid setting the latter flag in this case. PR c++/91859 gcc/ChangeLog: * tree.h (CALL_FROM_NEW_OR_DELETE_P): Adjust comment. gcc/cp/ChangeLog: * call.c (build_op_delete_call): Don't set CALL_FROM_NEW_OR_DELETE_P for destroying delete. * init.c (build_delete): Don't clobber before destroying delete. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/destroying-delete5.C: New test. --- gcc/cp/call.c | 4 +++- gcc/cp/init.c | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index bf524b5..90192b1 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -7206,8 +7206,10 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, treat that as an implicit delete-expression. This is also called for the delete if the constructor throws in a new-expression, and for a deleting destructor (which implements a delete-expression). */ + /* But leave this flag off for destroying delete to avoid wrong + assumptions in the optimizers. */ tree call = extract_call_expr (ret); - if (TREE_CODE (call) == CALL_EXPR) + if (TREE_CODE (call) == CALL_EXPR && !destroying_delete_p (fn)) CALL_FROM_NEW_OR_DELETE_P (call) = 1; return ret; diff --git a/gcc/cp/init.c b/gcc/cp/init.c index a85f4d5..04d4958 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -4881,7 +4881,10 @@ build_delete (location_t loc, tree otype, tree addr, complain); } - if (!destroying_delete && type_build_dtor_call (type)) + if (destroying_delete) + /* The operator delete will call the destructor. */ + expr = addr; + else if (type_build_dtor_call (type)) expr = build_dtor_call (cp_build_fold_indirect_ref (addr), auto_delete, flags, complain); else -- cgit v1.1 From ac0bc21bd634a334ba8f323c39a11f01dfdc2aae Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 1 Jun 2021 12:23:49 -0400 Subject: c++: value-init vs zero-init in expand_aggr_init_1 [PR65816] In the case of value-initializing an object of class type T, [dcl.init.general]/8 says: - if T has either no default constructor ([class.default.ctor]) or a default constructor that is user-provided or deleted, then the object is default-initialized; - otherwise, the object is zero-initialized and ... if T has a non-trivial default constructor, the object is default-initialized; But when determining whether to first zero-initialize the object, expand_aggr_init_1 incorrectly considers the user-providedness of _all_ constructors rather than only that of the _default_ constructors. This causes us to skip the zero-initialization step when the class type has a defaulted default constructor alongside a user-defined constructor. It seems the predicate type_has_non_user_provided_default_constructor accurately captures the above rule for when to first perform a zero-initialization during value-initialization, so this patch adjusts expand_aggr_init_1 to use this predicate instead. PR c++/65816 gcc/cp/ChangeLog: * init.c (expand_aggr_init_1): Check type_has_non_user_provided_default_constructor instead of type_has_user_provided_constructor. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-delegating3.C: New test. * g++.dg/cpp0x/dc10.C: New test. * g++.dg/cpp0x/initlist-base4.C: New test. * g++.dg/cpp2a/constexpr-init22.C: New test. libstdc++-v3/ChangeLog: * testsuite/23_containers/deque/allocator/default_init.cc, testsuite/23_containers/forward_list/allocator/default_init.cc, testsuite/23_containers/list/allocator/default_init.cc, testsuite/23_containers/map/allocator/default_init.cc, testsuite/23_containers/set/allocator/default_init.cc, testsuite/23_containers/vector/allocator/default_init.cc, testsuite/23_containers/vector/bool/allocator/default_init.cc: Remove xfail. --- gcc/cp/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 04d4958..b112328 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2078,9 +2078,9 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, that's value-initialization. */ if (init == void_type_node) { - /* If the type has data but no user-provided ctor, we need to zero + /* If the type has data but no user-provided default ctor, we need to zero out the object. */ - if (!type_has_user_provided_constructor (type) + if (type_has_non_user_provided_default_constructor (type) && !is_really_empty_class (type, /*ignore_vptr*/true)) { tree field_size = NULL_TREE; -- cgit v1.1 From b75978d14fc35981ffd8bf060ee52300db4dae50 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 2 Jun 2021 00:16:43 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c764713..9a5fa79 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,22 @@ +2021-06-01 Patrick Palka + + PR c++/65816 + * init.c (expand_aggr_init_1): Check + type_has_non_user_provided_default_constructor instead of + type_has_user_provided_constructor. + +2021-06-01 Jason Merrill + + PR c++/91859 + * call.c (build_op_delete_call): Don't set CALL_FROM_NEW_OR_DELETE_P + for destroying delete. + * init.c (build_delete): Don't clobber before destroying delete. + +2021-06-01 Jason Merrill + + PR c++/94492 + * decl2.c (cp_warn_deprecated_use): Check warning_enabled_at. + 2021-05-31 Richard Biener PR c++/88601 -- cgit v1.1 From 63d182b29306e582bfb151cf762820211ea1cc7e Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 31 May 2021 12:36:25 -0400 Subject: c++: missing dtor with -fno-elide-constructors [PR100838] tf_no_cleanup only applies to the outermost TARGET_EXPR, and we already clear it for nested calls in build_over_call, but in this case both constructor calls came from convert_like, so we need to clear it in the recursive call as well. This revealed that we were adding an extra ck_rvalue in direct-initialization cases where it was wrong. PR c++/100838 gcc/cp/ChangeLog: * call.c (convert_like_internal): Clear tf_no_cleanup when recursing. (build_user_type_conversion_1): Only add ck_rvalue if LOOKUP_ONLYCONVERTING. gcc/testsuite/ChangeLog: * g++.dg/init/no-elide2.C: New test. --- gcc/cp/call.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 90192b1..17fc60c 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4110,7 +4110,7 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags, { cand->second_conv = build_identity_conv (totype, NULL_TREE); - /* If totype isn't a reference, and LOOKUP_NO_TEMP_BIND isn't + /* If totype isn't a reference, and LOOKUP_ONLYCONVERTING is set, then this is copy-initialization. In that case, "The result of the call is then used to direct-initialize the object that is the destination of the copy-initialization." @@ -4119,6 +4119,8 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags, We represent this in the conversion sequence with an rvalue conversion, which means a constructor call. */ if (!TYPE_REF_P (totype) + && cxx_dialect < cxx17 + && (flags & LOOKUP_ONLYCONVERTING) && !(convflags & LOOKUP_NO_TEMP_BIND)) cand->second_conv = build_conv (ck_rvalue, totype, cand->second_conv); @@ -7800,7 +7802,7 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, expr = convert_like (next_conversion (convs), expr, fn, argnum, convs->kind == ck_ref_bind ? issue_conversion_warnings : false, - c_cast_p, complain); + c_cast_p, complain & ~tf_no_cleanup); if (expr == error_mark_node) return error_mark_node; -- cgit v1.1 From 9663c744e2d0942f14eafa725a1bd9f766f02a16 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 3 Jun 2021 00:16:23 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9a5fa79..e40cc6b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2021-06-02 Jason Merrill + + PR c++/100838 + * call.c (convert_like_internal): Clear tf_no_cleanup when + recursing. + (build_user_type_conversion_1): Only add ck_rvalue if + LOOKUP_ONLYCONVERTING. + 2021-06-01 Patrick Palka PR c++/65816 -- 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/pt.c | 1 + gcc/cp/semantics.c | 28 +++++++++++++--------------- 2 files changed, 14 insertions(+), 15 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3130280..15ef488 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17399,6 +17399,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_UNIFORM: case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_AFFINITY: case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: case OMP_CLAUSE_MAP: 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 69f517ac20566a645ff41a9bfca535822205a538 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 3 Jun 2021 09:37:11 -0400 Subject: c++: using-enum and access specifiers [PR100862] When copying the enumerators imported by a class-scope using-enum declaration, we need to override current_access_specifier so that finish_member_declaration gives the copies the same access as the using-enum decl. (A class-scope using-enum is processed late, so current_access_specifier at this point is otherwise set to the last access specifier within the class.) To that end, this patch makes handle_using_decl call set_current_access_from_decl accordingly. For consistency, this patch makes build_enumerator use set_current_access_from_decl too. PR c++/100862 gcc/cp/ChangeLog: * pt.c (set_current_access_from_decl): Move to ... * class.c (set_current_access_from_decl): ... here. (handle_using_decl): Use it to propagate the access of the using-enum decl to the copy of the imported enumerator. * cp-tree.h (set_current_access_from_decl): Declare. * decl.c (build_enumerator): Simplify using make_temp_override and set_current_access_from_decl. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/using-enum-9.C: New test. --- gcc/cp/class.c | 15 +++++++++++++++ gcc/cp/cp-tree.h | 1 + gcc/cp/decl.c | 12 ++---------- gcc/cp/pt.c | 14 -------------- 4 files changed, 18 insertions(+), 24 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 354addd..b53a4db 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -207,6 +207,19 @@ static bool type_maybe_constexpr_default_constructor (tree); static bool type_maybe_constexpr_destructor (tree); static bool field_poverlapping_p (tree); +/* Set CURRENT_ACCESS_SPECIFIER based on the protection of DECL. */ + +void +set_current_access_from_decl (tree decl) +{ + if (TREE_PRIVATE (decl)) + current_access_specifier = access_private_node; + else if (TREE_PROTECTED (decl)) + current_access_specifier = access_protected_node; + else + current_access_specifier = access_public_node; +} + /* Return a COND_EXPR that executes TRUE_STMT if this execution of the 'structor is in charge of 'structing virtual bases, or FALSE_STMT otherwise. */ @@ -1359,6 +1372,8 @@ handle_using_decl (tree using_decl, tree t) CONST_DECL_USING_P is true. */ gcc_assert (TREE_CODE (decl) == CONST_DECL); + auto cas = make_temp_override (current_access_specifier); + set_current_access_from_decl (using_decl); tree copy = copy_decl (decl); DECL_CONTEXT (copy) = t; DECL_ARTIFICIAL (copy) = true; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index c95a820..b1b7e61 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8186,6 +8186,7 @@ struct atom_hasher : default_hash_traits extern bool subsumes (tree, tree); /* In class.c */ +extern void set_current_access_from_decl (tree); extern void cp_finish_injected_record_type (tree); /* in vtable-class-hierarchy.c */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index e7268d5..fb21a3a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -16333,17 +16333,9 @@ incremented enumerator value is too large for %")); For which case we need to make sure that the access of `S::i' matches the access of `S::E'. */ - tree saved_cas = current_access_specifier; - if (TREE_PRIVATE (TYPE_NAME (enumtype))) - current_access_specifier = access_private_node; - else if (TREE_PROTECTED (TYPE_NAME (enumtype))) - current_access_specifier = access_protected_node; - else - current_access_specifier = access_public_node; - + auto cas = make_temp_override (current_access_specifier); + set_current_access_from_decl (TYPE_NAME (enumtype)); finish_member_declaration (decl); - - current_access_specifier = saved_cas; } else pushdecl (decl); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 15ef488..7211bdc 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -190,7 +190,6 @@ static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree); static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree); static bool check_specialization_scope (void); static tree process_partial_specialization (tree); -static void set_current_access_from_decl (tree); static enum template_base_result get_template_base (tree, tree, tree, tree, bool , tree *); static tree try_class_unification (tree, tree, tree, tree, bool); @@ -26432,19 +26431,6 @@ tsubst_initializer_list (tree t, tree argvec) return inits; } -/* Set CURRENT_ACCESS_SPECIFIER based on the protection of DECL. */ - -static void -set_current_access_from_decl (tree decl) -{ - if (TREE_PRIVATE (decl)) - current_access_specifier = access_private_node; - else if (TREE_PROTECTED (decl)) - current_access_specifier = access_protected_node; - else - current_access_specifier = access_public_node; -} - /* Instantiate an enumerated type. TAG is the template type, NEWTAG is the instantiation (which should have been created with start_enum) and ARGS are the template arguments to use. */ -- cgit v1.1 From d999d9b7e53b9a9cd2004a19e84c637e5e5013f5 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 3 Jun 2021 09:39:13 -0400 Subject: c++: cv-qualified dependent name of alias tmpl [PR100592] Here, the dependent template name in the return type of f() resolves to an alias of int& after substitution, and we end up complaining about qualifying this reference type with 'const' from cp_build_qualified_type rather than just silently dropping the qualification as per [dcl.ref]/1. The problem is ultimately that make_typename_type ignores the tf_keep_type_decl flag when the dependent name is a template-id. This in turn causes the TYPE_DECL check within tsubst to fail, and so we end up not passing tf_ignore_bad_quals to cp_build_qualified_type. This patch fixes this by making make_typename_type respect the tf_keep_type_decl flag in this situation. PR c++/100592 gcc/cp/ChangeLog: * decl.c (make_typename_type): After calling lookup_template_class, adjust the result to its TYPE_NAME and then consider the tf_keep_type_decl flag. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/alias-decl-71.C: New test. --- gcc/cp/decl.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index fb21a3a..a3687db 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4136,10 +4136,15 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, return error_mark_node; if (want_template) - return lookup_template_class (t, TREE_OPERAND (fullname, 1), - NULL_TREE, context, - /*entering_scope=*/0, - complain | tf_user); + { + t = lookup_template_class (t, TREE_OPERAND (fullname, 1), + NULL_TREE, context, + /*entering_scope=*/0, + complain | tf_user); + if (t == error_mark_node) + return error_mark_node; + t = TYPE_NAME (t); + } if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl)) t = TREE_TYPE (t); -- cgit v1.1 From 440c8a0a91b7ea1603e3e1eaae64fc0e12f0c4f1 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 4 Jun 2021 00:16:24 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e40cc6b..6c0f38c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,33 @@ +2021-06-03 Patrick Palka + + PR c++/100592 + * decl.c (make_typename_type): After calling + lookup_template_class, adjust the result to its TYPE_NAME and + then consider the tf_keep_type_decl flag. + +2021-06-03 Patrick Palka + + PR c++/100862 + * pt.c (set_current_access_from_decl): Move to ... + * class.c (set_current_access_from_decl): ... here. + (handle_using_decl): Use it to propagate the access of the + using-enum decl to the copy of the imported enumerator. + * cp-tree.h (set_current_access_from_decl): Declare. + * decl.c (build_enumerator): Simplify using make_temp_override + and set_current_access_from_decl. + +2021-06-03 Jakub Jelinek + + PR c++/100859 + * 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. + 2021-06-02 Jason Merrill PR c++/100838 -- cgit v1.1 From 3011f1046628d5ce5e6e5f8e917a6aea1385fdc3 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 4 Jun 2021 11:17:05 +0200 Subject: c++: Fix up attribute handling in methods in templates [PR100872] The following testcase FAILs because a dependent (late) attribute is never tsubsted. While the testcase is OpenMP, I think it is a generic C++ FE problem that could affect any other dependent attribute. apply_late_template_attributes documents that it relies on /* save_template_attributes puts the dependent attributes at the beginning of the list; find the non-dependent ones. */ The "operator binding" attributes that are sometimes added are added to the head of DECL_ATTRIBUTES list though and because it doesn't have ATTR_IS_DEPENDENT set it violates this requirement. The following patch fixes it by adding that attribute after all ATTR_IS_DEPENDENT attributes. I'm not 100% sure if DECL_ATTRIBUTES can't be shared by multiple functions (e.g. the cdtor clones), but the code uses later remove_attribute which could break that too. Other option would be to copy_list the ATTR_IS_DEPENDENT portion of the DECL_ATTRIBUTES list if we need to do this, that would be the same as this patch but replace that *ap = op_attr; at the end with *ap = NULL_TREE; DECL_ATTRIBUTES (cfn) = chainon (copy_list (DECL_ATTRIBUTES (cfn)), op_attr); Or perhaps set ATTR_IS_DEPENDENT on the "operator bindings" attribute, though it would need to be studied what would it try to do with the attribute during tsubst. 2021-06-04 Jakub Jelinek PR c++/100872 * name-lookup.c (maybe_save_operator_binding): Add op_attr after all ATTR_IS_DEPENDENT attributes in the DECL_ATTRIBUTES list rather than to the start. * g++.dg/gomp/declare-simd-8.C: New test. --- gcc/cp/name-lookup.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index a6c9e68..241ad2b 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -9136,9 +9136,12 @@ maybe_save_operator_binding (tree e) tree op_attr = lookup_attribute (op_bind_attrname, attributes); if (!op_attr) { + tree *ap = &DECL_ATTRIBUTES (cfn); + while (*ap && ATTR_IS_DEPENDENT (*ap)) + ap = &TREE_CHAIN (*ap); op_attr = tree_cons (get_identifier (op_bind_attrname), - NULL_TREE, attributes); - DECL_ATTRIBUTES (cfn) = op_attr; + NULL_TREE, *ap); + *ap = op_attr; } tree op_bind = purpose_member (fnname, TREE_VALUE (op_attr)); -- cgit v1.1 From 5357ab75dedef403b0eebf9277d61d1cbeb5898f Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 4 Jun 2021 13:46:53 -0400 Subject: c++: tsubst_function_decl and excess arg levels [PR100102] Here, when instantiating the dependent alias template duration::__is_harmonic with args={{T,U},{int}}, we find ourselves substituting the function decl _S_gcd. Since we have more arg levels than _S_gcd has parm levels, an old special case in tsubst_function_decl causes us to unwantedly reduce args to its innermost level, yielding args={int}, which leads to a nonsensical substitution into the decl context and eventually a crash. The comment for this special case refers to three examples for which we ought to see more arg levels than parm levels here, but none of the examples actually demonstrate this. In the first example, when defining S::f(U) parms_depth is 2 and args_depth is 1, and later when instantiating say S::f both depths are 2. In the second example, when substituting the template friend declaration parms_depth is 2 and args_depth is 1, and later when instantiating f both depths are 1. Finally, the third example is invalid since we can't specialize a member template of an unspecialized class template like that. Given that this reduction code seems no longer relevant for its documented purpose and that it causes problems as in the PR, this patch just removes it. Note that as far as bootstrap/regtest is concerned, this code is dead; the below two tests would be the first to reach it. PR c++/100102 gcc/cp/ChangeLog: * pt.c (tsubst_function_decl): Remove old code for reducing args when it has excess levels. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/alias-decl-72.C: New test. * g++.dg/cpp0x/alias-decl-72a.C: New test. --- gcc/cp/pt.c | 39 --------------------------------------- 1 file changed, 39 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7211bdc..744461e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13905,45 +13905,6 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash)) return spec; } - - /* We can see more levels of arguments than parameters if - there was a specialization of a member template, like - this: - - template struct S { template void f(); } - template <> template void S::f(U); - - Here, we'll be substituting into the specialization, - because that's where we can find the code we actually - want to generate, but we'll have enough arguments for - the most general template. - - We also deal with the peculiar case: - - template struct S { - template friend void f(); - }; - template void f() {} - template S; - template void f(); - - Here, the ARGS for the instantiation of will be {int, - double}. But, we only need as many ARGS as there are - levels of template parameters in CODE_PATTERN. We are - careful not to get fooled into reducing the ARGS in - situations like: - - template struct S { template void f(U); } - template template <> void S::f(int) {} - - which we can spot because the pattern will be a - specialization in this case. */ - int args_depth = TMPL_ARGS_DEPTH (args); - int parms_depth = - TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (t))); - - if (args_depth > parms_depth && !DECL_TEMPLATE_SPECIALIZATION (t)) - args = get_innermost_template_args (args, parms_depth); } else { -- cgit v1.1 From 6f8c9691495ad5a307db98dc19c3296ee4e6de64 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 4 Jun 2021 14:08:26 -0400 Subject: c++: top-level cv-quals on type of NTTP [PR100893] Here, we're rejecting the specialization of g with T=A, F=&f in param4.C below due to a spurious constness mismatch between the type of the template argument &f and the substituted type of the parm F (the latter has a top-level const). Note that this mismatch doesn't occur with object pointers because in that case a call to perform_qualification_conversions from convert_nontype_argument implicitly adds a top-level const to the argument (via a cast) to match. This however seems to be a manifestation of a more general conformance issue: we're not dropping top-level cv-quals on the substituted type of an NTTP as per [temp.param]/6 (we only do so at parse time in process_template_parm). So this patch makes convert_template_argument drop top-level cv-quals accordingly. PR c++/100893 gcc/cp/ChangeLog: * pt.c (convert_template_argument): Strip top-level cv-quals on the substituted type of a non-type template parameter. gcc/testsuite/ChangeLog: * g++.dg/template/param4.C: New test. * g++.dg/template/param5.C: New test. * g++.dg/cpp1z/nontype-auto19.C: New test. * g++.dg/cpp2a/concepts-decltype.C: Don't expect that the deduced type of a decltype(auto) NTTP has top-level cv-quals. --- gcc/cp/pt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 744461e..2ae886d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8499,6 +8499,10 @@ convert_template_argument (tree parm, if (invalid_nontype_parm_type_p (t, complain)) return error_mark_node; + /* Drop top-level cv-qualifiers on the substituted/deduced type of + this non-type template parameter, as per [temp.param]/6. */ + t = cv_unqualified (t); + if (t != TREE_TYPE (parm)) t = canonicalize_type_argument (t, complain); -- cgit v1.1 From 600f90cbbbf2f1e4511d72a23a5d637d11e9f28b Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 5 Jun 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6c0f38c..f1537e5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,22 @@ +2021-06-04 Patrick Palka + + PR c++/100893 + * pt.c (convert_template_argument): Strip top-level cv-quals + on the substituted type of a non-type template parameter. + +2021-06-04 Patrick Palka + + PR c++/100102 + * pt.c (tsubst_function_decl): Remove old code for reducing + args when it has excess levels. + +2021-06-04 Jakub Jelinek + + PR c++/100872 + * name-lookup.c (maybe_save_operator_binding): Add op_attr after all + ATTR_IS_DEPENDENT attributes in the DECL_ATTRIBUTES list rather than + to the start. + 2021-06-03 Patrick Palka PR c++/100592 -- cgit v1.1 From 7fa4db39b6bcd207bd2bffff52023ff6b155bd15 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sun, 6 Jun 2021 19:37:06 +0200 Subject: openmp: Call c_omp_adjust_map_clauses even for combined target [PR100902] When looking at in_reduction support for target, I've noticed that c_omp_adjust_map_clauses is not called for the combined target case. The following patch fixes it. Unfortunately, there are other issues. One is (also mentioned in the PR) that currently the pointer attachment stuff seems to be clause ordering dependent (the standard says that clause ordering on the same construct does not matter), the baz and qux cases in the PR are rejected while when swapped it is accepted. Note, the order of clauses in GCC really is treated as insignificant initially and only later on the compiler can adjust the ordering (e.g. when we sort map clauses based on what they refer to etc.) and in particular, clauses from parsing is reverse of the order in user code, while c_omp_split_clauses performed for combined/composite constructs typically reverses that ordering, i.e. makes it follow the user code ordering. And another one is I'm slightly afraid c_omp_adjust_map_clauses might misbehave in templates, though haven't tried to verify it with testcases. When processing_template_decl, the non-dependent clauses will be handled usually the same as when not in a template, but dependent clauses aren't processed or only limited processing is done there, and rest is deferred till later. From quick skimming of c_omp_adjust_map_clauses, it seems it might not be very happy about non-processed map clauses that might still have the TREE_LIST representation of array sections, or might not have finalized decls or base decls etc. So, for this I wonder if cp_parser_omp_target (and other cp/parser.c callers of c_omp_adjust_map_clauses) shouldn't call it only if (!processing_template_decl) - perhaps you could add cp_omp_adjust_map_clauses wrapper that would be if (!processing_template_decl) c_omp_adjust_map_clauses (...); - and call c_omp_adjust_map_clauses from within pt.c after the clauses are tsubsted and finish_omp_clauses is called again. 2021-06-06 Jakub Jelinek PR c/100902 * c-parser.c (c_parser_omp_target): Call c_omp_adjust_map_clauses even when target is combined with other constructs. * parser.c (cp_parser_omp_target): Call c_omp_adjust_map_clauses even when target is combined with other constructs. * c-c++-common/gomp/pr100902-1.c: New test. --- gcc/cp/parser.c | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4a46828..0649bf9 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -42233,6 +42233,7 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, tree stmt = make_node (OMP_TARGET); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; + c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); OMP_TARGET_BODY (stmt) = body; OMP_TARGET_COMBINED (stmt) = 1; SET_EXPR_LOCATION (stmt, pragma_tok->location); -- cgit v1.1 From 7d6987e90d1181de8dc51f9ba2313052faea080e Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Mon, 7 Jun 2021 00:16:23 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f1537e5..7542375 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2021-06-06 Jakub Jelinek + + PR c/100902 + * parser.c (cp_parser_omp_target): Call c_omp_adjust_map_clauses + even when target is combined with other constructs. + 2021-06-04 Patrick Palka PR c++/100893 -- cgit v1.1 From 6cb35b606c39d5f21f3298c77bfbcaaef3fbc872 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 7 Jun 2021 12:02:08 -0400 Subject: c++: access of dtor named by qualified template-id [PR100918] Here, when resolving the destructor named by Inner::~Inner (which is valid until C++20) we end up in cp_parser_lookup_name called indirectly from cp_parser_template_id to look up the name Inner from the scope Inner. The lookup naturally finds the injected-class-name, and because the flag is_template is true, we adjust this lookup result to the TEMPLATE_DECL Inner. We then check access of this adjusted lookup result. But this access check fails because the lookup scope is Inner and the context_for_name_lookup for the TEMPLATE_DECL is Outer (whereas for the injected-class-name it's also Inner). The simplest fix seems to be to check access of the original lookup result (the injected-class-name) instead of the adjusted result (the TEMPLATE_DECL). So this patch moves the access check in cp_parser_lookup_name to before the injected-class-name adjustment. PR c++/100918 gcc/cp/ChangeLog: * parser.c (cp_parser_lookup_name): Check access of the lookup result before we potentially adjust an injected-class-name to its TEMPLATE_DECL. gcc/testsuite/ChangeLog: * g++.dg/template/access38.C: New test. --- gcc/cp/parser.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0649bf9..24f248a 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -29505,6 +29505,19 @@ cp_parser_lookup_name (cp_parser *parser, tree name, if (!decl || decl == error_mark_node) return error_mark_node; + /* If we have resolved the name of a member declaration, check to + see if the declaration is accessible. When the name resolves to + set of overloaded functions, accessibility is checked when + overload resolution is done. If we have a TREE_LIST, then the lookup + is either ambiguous or it found multiple injected-class-names, the + accessibility of which is trivially satisfied. + + During an explicit instantiation, access is not checked at all, + as per [temp.explicit]. */ + if (DECL_P (decl)) + check_accessibility_of_qualified_id (decl, object_type, parser->scope, + tf_warning_or_error); + /* Pull out the template from an injected-class-name (or multiple). */ if (is_template) decl = maybe_get_template_decl_from_type_decl (decl); @@ -29531,17 +29544,6 @@ cp_parser_lookup_name (cp_parser *parser, tree name, || TREE_CODE (decl) == UNBOUND_CLASS_TEMPLATE || BASELINK_P (decl)); - /* If we have resolved the name of a member declaration, check to - see if the declaration is accessible. When the name resolves to - set of overloaded functions, accessibility is checked when - overload resolution is done. - - During an explicit instantiation, access is not checked at all, - as per [temp.explicit]. */ - if (DECL_P (decl)) - check_accessibility_of_qualified_id (decl, object_type, parser->scope, - tf_warning_or_error); - maybe_record_typedef_use (decl); return cp_expr (decl, name_location); -- cgit v1.1 From 438aac594e1c5ad32b787e8753b3893044ecf26f Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 8 Jun 2021 00:16:44 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7542375..225b8917 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2021-06-07 Patrick Palka + + PR c++/100918 + * parser.c (cp_parser_lookup_name): Check access of the lookup + result before we potentially adjust an injected-class-name to + its TEMPLATE_DECL. + 2021-06-06 Jakub Jelinek PR c/100902 -- cgit v1.1 From a1b3484a8e6c53c8084723e3f1738d402374198e Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 31 May 2021 12:56:34 -0400 Subject: c++: alias member template [PR100102] Patrick already fixed the primary cause of this bug. But while I was looking at this testcase I noticed that with the qualified name k::o we ended up with a plain FUNCTION_DECL, whereas without the k:: we got a BASELINK. There seems to be no good reason not to return the BASELINK in this case as well. PR c++/100102 gcc/cp/ChangeLog: * init.c (build_offset_ref): Return the BASELINK for a static member function. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/alias-decl-73.C: New test. --- gcc/cp/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index b112328..1b161d5 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2214,7 +2214,7 @@ build_offset_ref (tree type, tree member, bool address_p, if (!ok) return error_mark_node; if (DECL_STATIC_FUNCTION_P (t)) - return t; + return member; member = t; } else -- cgit v1.1 From 715614ec3ec5390293e508bb190335d28db1fa8b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 7 Jun 2021 17:51:24 -0400 Subject: c++: fix modules binfo merging My coming fix for PR91706 caused some regressions in the modules testsuite. This turned out to be because the change to properly use the base subobject BINFO as BASELINK_BINFO hit problems with the code for merging binfos. The tree reader needed a typo fix. The duplicate_hash function was crashing on the BINFO for a variadic base in . I started fixing the hash function, but then noticed that there's no ::equal function defined; duplicate_hash just uses pointer equality, so we might as well also use the normal pointer hash for the moment. gcc/cp/ChangeLog: * module.cc (duplicate_hash::hash): Comment out. (trees_in::tree_value): Adjust loop counter. --- gcc/cp/module.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index f0fb014..f259515 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -2820,12 +2820,16 @@ struct merge_key { struct duplicate_hash : nodel_ptr_hash { +#if 0 + /* This breaks variadic bases in the xtreme_header tests. Since ::equal is + the default pointer_hash::equal, let's use the default hash as well. */ inline static hashval_t hash (value_type decl) { if (TREE_CODE (decl) == TREE_BINFO) decl = TYPE_NAME (BINFO_TYPE (decl)); return hashval_t (DECL_UID (decl)); } +#endif }; /* Hashmap of merged duplicates. Usually decls, but can contain @@ -8908,7 +8912,7 @@ trees_in::tree_value () dump (dumper::MERGE) && dump ("Deduping binfo %N[%u]", type, ix); existing = TYPE_BINFO (type); - while (existing && ix) + while (existing && ix--) existing = TREE_CHAIN (existing); if (existing) register_duplicate (t, existing); -- 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') 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 1a98f830332e5a623278aaeea39c2a88177b2a9a Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 16 Apr 2021 13:52:02 -0400 Subject: c++: preserve BASELINK from lookup [PR91706] In the earlier patch for PR91706 I fixed the BASELINK built by baselink_for_fns, but since we already had one from lookup, we should keep that one around instead of stripping it. The removed hunk in get_class_binding was a wierdly large amount of code to decide whether to pull out BASELINK_FUNCTIONS. gcc/cp/ChangeLog: PR c++/91706 * name-lookup.c (get_class_binding): Keep a BASELINK. (set_inherited_value_binding_p): Adjust. * lambda.c (is_lambda_ignored_entity): Adjust. * pt.c (lookup_template_function): Copy a BASELINK before modifying it. --- gcc/cp/lambda.c | 6 +++--- gcc/cp/name-lookup.c | 24 +----------------------- gcc/cp/pt.c | 1 + 3 files changed, 5 insertions(+), 26 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 4a1e090..2e9d38b 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -1338,9 +1338,9 @@ is_lambda_ignored_entity (tree val) /* None of the lookups that use qualify_lookup want the op() from the lambda; they want the one from the enclosing class. */ - val = OVL_FIRST (val); - if (LAMBDA_FUNCTION_P (val)) - return true; + if (tree fns = maybe_get_fns (val)) + if (LAMBDA_FUNCTION_P (OVL_FIRST (fns))) + return true; return false; } diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 241ad2b..1be5f3d 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -5236,7 +5236,7 @@ set_inherited_value_binding_p (cxx_binding *binding, tree decl, { tree context; - if (TREE_CODE (decl) == OVERLOAD) + if (is_overloaded_fn (decl)) context = ovl_scope (decl); else { @@ -5338,28 +5338,6 @@ get_class_binding (tree name, cp_binding_level *scope) /*protect=*/2, /*want_type=*/false, tf_warning_or_error); - if (value_binding - && (TREE_CODE (value_binding) == TYPE_DECL - || DECL_CLASS_TEMPLATE_P (value_binding) - || (TREE_CODE (value_binding) == TREE_LIST - && TREE_TYPE (value_binding) == error_mark_node - && (TREE_CODE (TREE_VALUE (value_binding)) - == TYPE_DECL)))) - /* We found a type binding, even when looking for a non-type - binding. This means that we already processed this binding - above. */ - ; - else if (value_binding) - { - if (TREE_CODE (value_binding) == TREE_LIST - && TREE_TYPE (value_binding) == error_mark_node) - /* NAME is ambiguous. */ - ; - else if (BASELINK_P (value_binding)) - /* NAME is some overloaded functions. */ - value_binding = BASELINK_FUNCTIONS (value_binding); - } - /* If we found either a type binding or a value binding, create a new binding object. */ if (type_binding || value_binding) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2ae886d..b0155a9 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9597,6 +9597,7 @@ lookup_template_function (tree fns, tree arglist) if (BASELINK_P (fns)) { + fns = copy_node (fns); BASELINK_FUNCTIONS (fns) = build2 (TEMPLATE_ID_EXPR, unknown_type_node, BASELINK_FUNCTIONS (fns), -- cgit v1.1 From 91349e57bbfd010156b9128b2ad751c8843e7245 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 8 Jun 2021 09:19:58 -0400 Subject: c++: braced-list overload resolution [PR100963] My PR969626 patch made us ignore template candidates when there's a perfect non-template candidate. In this case, we were considering B(int) a perfect match for B({0}), but the brace elision makes it imperfect. PR c++/100963 gcc/cp/ChangeLog: * call.c (perfect_conversion_p): Check check_narrowing. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/initlist124.C: New test. --- gcc/cp/call.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 17fc60c..d2f6ca8 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5880,6 +5880,9 @@ perfect_conversion_p (conversion *conv) next_conversion (conv)->type)) return false; } + if (conv->check_narrowing) + /* Brace elision is imperfect. */ + return false; return true; } -- cgit v1.1 From 924e02553af64b10c485711d635c0bc0265a8743 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 8 Jun 2021 14:38:42 -0400 Subject: c++: Test for mixed string literal concatenation From wg21.link/p2201r1 gcc/cp/ChangeLog: * parser.c (cp_parser_string_literal): Adjust diagnostic. gcc/testsuite/ChangeLog: * g++.dg/cpp23/mixed-concat1.C: New test. --- gcc/cp/parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 24f248a..d59a829 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -4378,8 +4378,8 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, rich_location rich_loc (line_table, tok->location); rich_loc.add_range (last_tok_loc); error_at (&rich_loc, - "unsupported non-standard concatenation " - "of string literals"); + "concatenation of string literals with " + "conflicting encoding prefixes"); } } -- cgit v1.1 From 1afa4facb9348cac0349ff9c30066aa25a3608f7 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Mon, 7 Jun 2021 16:06:00 -0400 Subject: c++: explicit() ignored on deduction guide [PR100065] When we have explicit() with a value-dependent argument, we can't evaluate it at parsing time, so cp_parser_function_specifier_opt stashes the argument into the decl-specifiers and grokdeclarator then stores it into explicit_specifier_map, which is then used when substituting the function decl. grokdeclarator stores it for constructors and conversion functions, but we also need to do it for deduction guides, otherwise we'll forget that we've seen an explicit-specifier as in the attached test. PR c++/100065 gcc/cp/ChangeLog: * decl.c (grokdeclarator): Store a value-dependent explicit-specifier even for deduction guides. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/explicit18.C: New test. --- gcc/cp/decl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index a3687db..cbf647d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -14043,6 +14043,8 @@ grokdeclarator (const cp_declarator *declarator, storage_class = sc_none; } } + if (declspecs->explicit_specifier) + store_explicit_specifier (decl, declspecs->explicit_specifier); } else { -- cgit v1.1 From c60387214593445d1514bf7852f27f4523458cda Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 9 Jun 2021 00:16:30 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 225b8917..5a97fc8 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,43 @@ +2021-06-08 Marek Polacek + + PR c++/100065 + * decl.c (grokdeclarator): Store a value-dependent + explicit-specifier even for deduction guides. + +2021-06-08 Jason Merrill + + * parser.c (cp_parser_string_literal): Adjust diagnostic. + +2021-06-08 Jason Merrill + + PR c++/100963 + * call.c (perfect_conversion_p): Check check_narrowing. + +2021-06-08 Jason Merrill + + PR c++/91706 + * name-lookup.c (get_class_binding): Keep a BASELINK. + (set_inherited_value_binding_p): Adjust. + * lambda.c (is_lambda_ignored_entity): Adjust. + * pt.c (lookup_template_function): Copy a BASELINK before + modifying it. + +2021-06-08 Jason Merrill + + PR c++/91706 + * semantics.c (baselink_for_fns): Fix BASELINK_BINFO. + +2021-06-08 Jason Merrill + + * module.cc (duplicate_hash::hash): Comment out. + (trees_in::tree_value): Adjust loop counter. + +2021-06-08 Jason Merrill + + PR c++/100102 + * init.c (build_offset_ref): Return the BASELINK for a static + member function. + 2021-06-07 Patrick Palka PR c++/100918 -- cgit v1.1 From 206db06ee380f490db0293af4ea7a4d590abd78c Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 10 Jun 2021 18:31:18 -0400 Subject: c++: normalization of non-templated return-type-req [PR100946] Here the satisfaction cache is conflating the satisfaction value of the two return-type-requirements because the corresponding constrained 'auto's have level 2, but they capture an empty current_template_parms. This ultimately causes the satisfaction cache to think the type constraint doesn't depend on the deduced type of the expression. When normalizing the constraints on an 'auto', the assumption made by normalize_placeholder_type_constraints is that the level of the 'auto' is one greater than the depth of the captured current_template_parms, an assumption which is not holding here. So this patch just makes n_p_t_c adjust the normalization context appropriately in this situation. PR c++/100946 gcc/cp/ChangeLog: * constraint.cc (normalize_placeholder_type_constraints): When normalizing a non-templated return-type-requirement, add a dummy level to initial_parms. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-return-req3.C: New test. --- gcc/cp/constraint.cc | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 03ce8eb..74b16d2 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3065,6 +3065,15 @@ normalize_placeholder_type_constraints (tree t, bool diag) scope for this placeholder type; use them as the initial template parameters for normalization. */ tree initial_parms = TREE_PURPOSE (ci); + + if (!initial_parms && TEMPLATE_TYPE_LEVEL (t) == 2) + /* This is a return-type-requirement of a non-templated requires-expression, + which are parsed under processing_template_decl == 1 and empty + current_template_parms; hence the 'auto' has level 2 and initial_parms + is empty. Fix up initial_parms to be consistent with the value of + processing_template_decl whence the 'auto' was created. */ + initial_parms = build_tree_list (size_int (1), make_tree_vec (0)); + /* The 'auto' itself is used as the first argument in its own constraints, and its level is one greater than its template depth. So in order to capture all used template parameters, we need to add an extra level of -- cgit v1.1 From edec2660ff4890ecf8cc191f7c92cf527de51fe2 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 10 Jun 2021 18:31:21 -0400 Subject: c++: matching deduced template template parameters [PR67829] During deduction, when the template of the argument for a bound ttp is a template template parameter, we need to consider the TEMPLATE_TEMPLATE_PARAMETER for matching rather than the TEMPLATE_DECL thereof, because the canonical form of a template template parameter as a template argument is the former tree, not the latter. PR c++/67829 gcc/cp/ChangeLog: * pt.c (unify) : When the TEMPLATE_DECL of a BOUND_TEMPLATE_TEMPLATE_PARM argument is a template template parameter, adjust to the TEMPLATE_TEMPLATE_PARAMETER before falling through. gcc/testsuite/ChangeLog: * g++.dg/template/ttp34.C: New test. * g++.dg/template/ttp34a.C: New test. * g++.dg/template/ttp34b.C: New test. --- gcc/cp/pt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b0155a9..d87382d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -23555,6 +23555,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, return 1; arg = TYPE_TI_TEMPLATE (arg); + if (DECL_TEMPLATE_TEMPLATE_PARM_P (arg)) + /* If the template is a template template parameter, use the + TEMPLATE_TEMPLATE_PARM for matching. */ + arg = TREE_TYPE (arg); /* Fall through to deduce template name. */ } -- 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/constexpr.c | 10 +++++++ gcc/cp/cp-tree.h | 1 + gcc/cp/semantics.c | 82 ++++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 79 insertions(+), 14 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 297f207..01b0c42 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5121,6 +5121,16 @@ var_in_constexpr_fn (tree t) && DECL_DECLARED_CONSTEXPR_P (ctx)); } +/* True if a function might be constexpr: either a function that was + declared constexpr, or a C++17 lambda op(). */ + +bool +maybe_constexpr_fn (tree t) +{ + return (DECL_DECLARED_CONSTEXPR_P (t) + || (cxx_dialect >= cxx17 && LAMBDA_FUNCTION_P (t))); +} + /* True if T was declared in a function that might be constexpr: either a function that was declared constexpr, or a C++17 lambda op(). */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b1b7e61..9ac8b52 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8244,6 +8244,7 @@ extern bool reduced_constant_expression_p (tree); extern bool is_instantiation_of_constexpr (tree); extern bool var_in_constexpr_fn (tree); extern bool var_in_maybe_constexpr_fn (tree); +extern bool maybe_constexpr_fn (tree); extern void explain_invalid_constexpr_fn (tree); extern vec cx_error_context (void); extern tree fold_sizeof_expr (tree); 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 43c35d0d90214171bd037741d525a0fde73b7755 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 11 Jun 2021 09:09:28 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5a97fc8..ee5ef36 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,27 @@ +2021-06-11 Marek Polacek + + PR c++/100995 + * 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. + +2021-06-10 Patrick Palka + + PR c++/67829 + * pt.c (unify) : When + the TEMPLATE_DECL of a BOUND_TEMPLATE_TEMPLATE_PARM argument is + a template template parameter, adjust to the + TEMPLATE_TEMPLATE_PARAMETER before falling through. + +2021-06-10 Patrick Palka + + PR c++/100946 + * constraint.cc (normalize_placeholder_type_constraints): When + normalizing a non-templated return-type-requirement, add a dummy + level to initial_parms. + 2021-06-08 Marek Polacek PR c++/100065 -- cgit v1.1 From 117c64266405e244da4dae3ae7b60905af63b955 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 11 Jun 2021 15:50:34 +0200 Subject: c++: Add C++23 consteval if support - P1938R3 [PR100974] The following patch implements consteval if support. There is a new IF_STMT_CONSTEVAL_P flag on IF_STMT and IF_COND is boolean_false_node to match the non-manifestly constant evaluation behavior, while constexpr evaluation special-cases it. Perhaps cleaner would be to set the condition to __builtin_is_constant_evaluated () call but we need the IF_STMT_CONSTEVAL_P flag anyway and the IL would be larger. And I'm not changing the libstdc++ side, where perhaps we could change std::is_constant_evaluated definition for #ifdef __cpp_if_consteval case to if consteval { return true; } else { return false; } but we need to keep it defined to __builtin_is_constant_evaluated () for C++20 or older. 2021-06-11 Jakub Jelinek PR c++/100974 gcc/c-family/ * c-cppbuiltin.c (c_cpp_builtins): Predefine __cpp_if_consteval for -std=c++2b for P1938R3 consteval if support. gcc/cp/ * cp-tree.h (struct saved_scope): Add consteval_if_p member. Formatting fix for the discarded_stmt comment. (in_consteval_if_p, IF_STMT_CONSTEVAL_P): Define. * parser.c (cp_parser_lambda_expression): Temporarily disable in_consteval_if_p when parsing lambda body. (cp_parser_selection_statement): Parse consteval if. * decl.c (struct named_label_entry): Add in_consteval_if member. (level_for_consteval_if): New function. (poplevel_named_label_1, check_previous_goto_1, check_goto): Handle consteval if. * constexpr.c (cxx_eval_builtin_function_call): Clarify in comment why CP_BUILT_IN_IS_CONSTANT_EVALUATED needs to *non_constant_p for !ctx->manifestly_const_eval. (cxx_eval_conditional_expression): For IF_STMT_CONSTEVAL_P evaluate condition as if it was __builtin_is_constant_evaluated call. (potential_constant_expression_1): For IF_STMT_CONSTEVAL_P always recurse on both branches. * cp-gimplify.c (genericize_if_stmt): Genericize IF_STMT_CONSTEVAL_P as the else branch. * pt.c (tsubst_expr) : Copy IF_STMT_CONSTEVAL_P. Temporarily set in_consteval_if_p when recursing on IF_STMT_CONSTEVAL_P then branch. (tsubst_lambda_expr): Temporarily disable in_consteval_if_p when instantiating lambda body. * call.c (immediate_invocation_p): Return false when in_consteval_if_p. gcc/testsuite/ * g++.dg/cpp23/consteval-if1.C: New test. * g++.dg/cpp23/consteval-if2.C: New test. * g++.dg/cpp23/consteval-if3.C: New test. * g++.dg/cpp23/consteval-if4.C: New test. * g++.dg/cpp23/consteval-if5.C: New test. * g++.dg/cpp23/consteval-if6.C: New test. * g++.dg/cpp23/consteval-if7.C: New test. * g++.dg/cpp23/consteval-if8.C: New test. * g++.dg/cpp23/consteval-if9.C: New test. * g++.dg/cpp23/consteval-if10.C: New test. * g++.dg/cpp23/feat-cxx2b.C: Add __cpp_if_consteval tests. --- gcc/cp/call.c | 1 + gcc/cp/constexpr.c | 36 +++++++++++++++--- gcc/cp/cp-gimplify.c | 8 +++- gcc/cp/cp-tree.h | 10 ++++- gcc/cp/decl.c | 27 +++++++++++++- gcc/cp/parser.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/cp/pt.c | 13 +++++++ 7 files changed, 187 insertions(+), 10 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index d2f6ca8..9f03534 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8840,6 +8840,7 @@ immediate_invocation_p (tree fn, int nargs) || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)) && (current_binding_level->kind != sk_function_parms || !current_binding_level->immediate_fn_ctx_p) + && !in_consteval_if_p /* As an exception, we defer std::source_location::current () invocations until genericization because LWG3396 mandates special behavior for it. */ diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 01b0c42..4f1c3d6 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1315,7 +1315,10 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, } /* For __builtin_is_constant_evaluated, defer it if not - ctx->manifestly_const_eval, otherwise fold it to true. */ + ctx->manifestly_const_eval (as sometimes we try to constant evaluate + without manifestly_const_eval even expressions or parts thereof which + will later be manifestly const_eval evaluated), otherwise fold it to + true. */ if (fndecl_built_in_p (fun, CP_BUILT_IN_IS_CONSTANT_EVALUATED, BUILT_IN_FRONTEND)) { @@ -3298,6 +3301,22 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t, /*lval*/false, non_constant_p, overflow_p); VERIFY_CONSTANT (val); + if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t)) + { + /* Evaluate the condition as if it was + if (__builtin_is_constant_evaluated ()), i.e. defer it if not + ctx->manifestly_const_eval (as sometimes we try to constant evaluate + without manifestly_const_eval even expressions or parts thereof which + will later be manifestly const_eval evaluated), otherwise fold it to + true. */ + if (ctx->manifestly_const_eval) + val = boolean_true_node; + else + { + *non_constant_p = true; + return t; + } + } /* Don't VERIFY_CONSTANT the other operands. */ if (integer_zerop (val)) val = TREE_OPERAND (t, 2); @@ -8809,10 +8828,17 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, return false; if (!processing_template_decl) tmp = cxx_eval_outermost_constant_expr (tmp, true); - if (integer_zerop (tmp)) - return RECUR (TREE_OPERAND (t, 2), want_rval); - else if (TREE_CODE (tmp) == INTEGER_CST) - return RECUR (TREE_OPERAND (t, 1), want_rval); + /* potential_constant_expression* isn't told if it is called for + manifestly_const_eval or not, so for consteval if always + process both branches as if the condition is not a known + constant. */ + if (TREE_CODE (t) != IF_STMT || !IF_STMT_CONSTEVAL_P (t)) + { + if (integer_zerop (tmp)) + return RECUR (TREE_OPERAND (t, 2), want_rval); + else if (TREE_CODE (tmp) == INTEGER_CST) + return RECUR (TREE_OPERAND (t, 1), want_rval); + } tmp = *jump_target; for (i = 1; i < 3; ++i) { diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 9079a5b..96d91b6 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -161,7 +161,13 @@ genericize_if_stmt (tree *stmt_p) if (!else_) else_ = build_empty_stmt (locus); - if (integer_nonzerop (cond) && !TREE_SIDE_EFFECTS (else_)) + /* consteval if has been verified not to have the then_/else_ blocks + entered by gotos/case labels from elsewhere, and as then_ block + can contain unfolded immediate function calls, we have to discard + the then_ block regardless of whether else_ has side-effects or not. */ + if (IF_STMT_CONSTEVAL_P (stmt)) + stmt = else_; + else if (integer_nonzerop (cond) && !TREE_SIDE_EFFECTS (else_)) stmt = then_; else if (integer_zerop (cond) && !TREE_SIDE_EFFECTS (then_)) stmt = else_; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9ac8b52..36f99cc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -478,6 +478,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR) CONSTRUCTOR_MUTABLE_POISON (in CONSTRUCTOR) OVL_HIDDEN_P (in OVERLOAD) + IF_STMT_CONSTEVAL_P (in IF_STMT) SWITCH_STMT_NO_BREAK_P (in SWITCH_STMT) LAMBDA_EXPR_CAPTURE_OPTIMIZED (in LAMBDA_EXPR) IMPLICIT_CONV_EXPR_BRACED_INIT (in IMPLICIT_CONV_EXPR) @@ -1813,9 +1814,12 @@ struct GTY(()) saved_scope { BOOL_BITFIELD x_processing_explicit_instantiation : 1; BOOL_BITFIELD need_pop_function_context : 1; -/* Nonzero if we are parsing the discarded statement of a constexpr - if-statement. */ + /* Nonzero if we are parsing the discarded statement of a constexpr + if-statement. */ BOOL_BITFIELD discarded_stmt : 1; + /* Nonzero if we are parsing or instantiating the compound-statement + of consteval if statement. */ + BOOL_BITFIELD consteval_if_p : 1; int unevaluated_operand; int inhibit_evaluation_warnings; @@ -1879,6 +1883,7 @@ extern GTY(()) struct saved_scope *scope_chain; #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation #define in_discarded_stmt scope_chain->discarded_stmt +#define in_consteval_if_p scope_chain->consteval_if_p #define current_ref_temp_count scope_chain->ref_temp_count @@ -5211,6 +5216,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define ELSE_CLAUSE(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 2) #define IF_SCOPE(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 3) #define IF_STMT_CONSTEXPR_P(NODE) TREE_LANG_FLAG_0 (IF_STMT_CHECK (NODE)) +#define IF_STMT_CONSTEVAL_P(NODE) TREE_LANG_FLAG_2 (IF_STMT_CHECK (NODE)) /* Like PACK_EXPANSION_EXTRA_ARGS, for constexpr if. IF_SCOPE is used while building an IF_STMT; IF_STMT_EXTRA_ARGS is used after it is complete. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index cbf647d..da254d8 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -222,6 +222,7 @@ struct GTY((for_user)) named_label_entry { bool in_omp_scope; bool in_transaction_scope; bool in_constexpr_if; + bool in_consteval_if; }; #define named_labels cp_function_chain->x_named_labels @@ -491,6 +492,16 @@ level_for_constexpr_if (cp_binding_level *b) && IF_STMT_CONSTEXPR_P (b->this_entity)); } +/* True if B is the level for the condition of a consteval if. */ + +static bool +level_for_consteval_if (cp_binding_level *b) +{ + return (b->kind == sk_cond && b->this_entity + && TREE_CODE (b->this_entity) == IF_STMT + && IF_STMT_CONSTEVAL_P (b->this_entity)); +} + /* Update data for defined and undefined labels when leaving a scope. */ int @@ -530,6 +541,8 @@ poplevel_named_label_1 (named_label_entry **slot, cp_binding_level *bl) case sk_block: if (level_for_constexpr_if (bl->level_chain)) ent->in_constexpr_if = true; + else if (level_for_consteval_if (bl->level_chain)) + ent->in_consteval_if = true; break; default: break; @@ -3391,6 +3404,7 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, bool complained = false; int identified = 0; bool saw_eh = false, saw_omp = false, saw_tm = false, saw_cxif = false; + bool saw_ceif = false; if (exited_omp) { @@ -3470,6 +3484,12 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, loc = EXPR_LOCATION (b->level_chain->this_entity); saw_cxif = true; } + else if (!saw_ceif && level_for_consteval_if (b->level_chain)) + { + inf = G_(" enters % statement"); + loc = EXPR_LOCATION (b->level_chain->this_entity); + saw_ceif = true; + } break; default: @@ -3551,12 +3571,13 @@ check_goto (tree decl) unsigned ix; if (ent->in_try_scope || ent->in_catch_scope || ent->in_transaction_scope - || ent->in_constexpr_if + || ent->in_constexpr_if || ent->in_consteval_if || ent->in_omp_scope || !vec_safe_is_empty (ent->bad_decls)) { diagnostic_t diag_kind = DK_PERMERROR; if (ent->in_try_scope || ent->in_catch_scope || ent->in_constexpr_if - || ent->in_transaction_scope || ent->in_omp_scope) + || ent->in_consteval_if || ent->in_transaction_scope + || ent->in_omp_scope) diag_kind = DK_ERROR; complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), &input_location, diag_kind); @@ -3602,6 +3623,8 @@ check_goto (tree decl) inform (input_location, " enters synchronized or atomic statement"); else if (ent->in_constexpr_if) inform (input_location, " enters % statement"); + else if (ent->in_consteval_if) + inform (input_location, " enters % statement"); } if (ent->in_omp_scope) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d59a829..686f98b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -10902,6 +10902,11 @@ cp_parser_lambda_expression (cp_parser* parser) bool discarded = in_discarded_stmt; in_discarded_stmt = 0; + /* Similarly the body of a lambda in immediate function context is not + in immediate function context. */ + bool save_in_consteval_if_p = in_consteval_if_p; + in_consteval_if_p = false; + /* By virtue of defining a local class, a lambda expression has access to the private variables of enclosing classes. */ @@ -10932,6 +10937,7 @@ cp_parser_lambda_expression (cp_parser* parser) finish_struct (type, /*attributes=*/NULL_TREE); + in_consteval_if_p = save_in_consteval_if_p; in_discarded_stmt = discarded; parser->num_template_parameter_lists = saved_num_template_parameter_lists; @@ -12324,6 +12330,102 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, "% only available with " "%<-std=c++17%> or %<-std=gnu++17%>"); } + int ce = 0; + if (keyword == RID_IF && !cx) + { + if (cp_lexer_next_token_is_keyword (parser->lexer, + RID_CONSTEVAL)) + ce = 1; + else if (cp_lexer_next_token_is (parser->lexer, CPP_NOT) + && cp_lexer_nth_token_is_keyword (parser->lexer, 2, + RID_CONSTEVAL)) + { + ce = -1; + cp_lexer_consume_token (parser->lexer); + } + } + if (ce) + { + cp_token *tok = cp_lexer_consume_token (parser->lexer); + if (cxx_dialect < cxx23) + pedwarn (tok->location, OPT_Wc__23_extensions, + "% only available with " + "%<-std=c++2b%> or %<-std=gnu++2b%>"); + + bool save_in_consteval_if_p = in_consteval_if_p; + statement = begin_if_stmt (); + IF_STMT_CONSTEVAL_P (statement) = true; + condition = finish_if_stmt_cond (boolean_false_node, statement); + + gcc_rich_location richloc = tok->location; + bool non_compound_stmt_p = false; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) + { + non_compound_stmt_p = true; + richloc.add_fixit_insert_after (tok->location, "{"); + } + + in_consteval_if_p |= ce > 0; + cp_parser_implicitly_scoped_statement (parser, NULL, guard_tinfo); + + if (non_compound_stmt_p) + { + location_t before_loc + = cp_lexer_peek_token (parser->lexer)->location; + richloc.add_fixit_insert_before (before_loc, "}"); + error_at (&richloc, + "% requires compound statement"); + non_compound_stmt_p = false; + } + + finish_then_clause (statement); + + /* If the next token is `else', parse the else-clause. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, + RID_ELSE)) + { + cp_token *else_tok = cp_lexer_peek_token (parser->lexer); + gcc_rich_location else_richloc = else_tok->location; + guard_tinfo = get_token_indent_info (else_tok); + /* Consume the `else' keyword. */ + cp_lexer_consume_token (parser->lexer); + + begin_else_clause (statement); + + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) + { + non_compound_stmt_p = true; + else_richloc.add_fixit_insert_after (else_tok->location, + "{"); + } + + in_consteval_if_p = save_in_consteval_if_p | (ce < 0); + cp_parser_implicitly_scoped_statement (parser, NULL, + guard_tinfo); + + if (non_compound_stmt_p) + { + location_t before_loc + = cp_lexer_peek_token (parser->lexer)->location; + else_richloc.add_fixit_insert_before (before_loc, "}"); + error_at (&else_richloc, + "% requires compound statement"); + } + + finish_else_clause (statement); + } + + in_consteval_if_p = save_in_consteval_if_p; + if (ce < 0) + { + std::swap (THEN_CLAUSE (statement), ELSE_CLAUSE (statement)); + if (THEN_CLAUSE (statement) == NULL_TREE) + THEN_CLAUSE (statement) = build_empty_stmt (tok->location); + } + + finish_if_stmt (statement); + return statement; + } /* Look for the `('. */ matching_parens parens; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d87382d..b53df9e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -18413,6 +18413,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case IF_STMT: stmt = begin_if_stmt (); IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t); + IF_STMT_CONSTEVAL_P (stmt) = IF_STMT_CONSTEVAL_P (t); if (IF_STMT_CONSTEXPR_P (t)) args = add_extra_args (IF_STMT_EXTRA_ARGS (t), args); tmp = RECUR (IF_COND (t)); @@ -18433,6 +18434,13 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, } if (IF_STMT_CONSTEXPR_P (t) && integer_zerop (tmp)) /* Don't instantiate the THEN_CLAUSE. */; + else if (IF_STMT_CONSTEVAL_P (t)) + { + bool save_in_consteval_if_p = in_consteval_if_p; + in_consteval_if_p = true; + RECUR (THEN_CLAUSE (t)); + in_consteval_if_p = save_in_consteval_if_p; + } else { tree folded = fold_non_dependent_expr (tmp, complain); @@ -19385,6 +19393,9 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) local_specialization_stack s (lss_copy); + bool save_in_consteval_if_p = in_consteval_if_p; + in_consteval_if_p = false; + tree body = start_lambda_function (fn, r); /* Now record them for lookup_init_capture_pack. */ @@ -19425,6 +19436,8 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) finish_lambda_function (body); + in_consteval_if_p = save_in_consteval_if_p; + if (nested) pop_function_context (); else -- cgit v1.1 From b0d73a66ae3962fa83309527d85613d72a6aa43d Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 11 Jun 2021 16:00:52 -0400 Subject: c++: Substitute into function parms in lexical order [PR96560] This makes tsubst_arg_types substitute into a function's parameter types in left-to-right instead of right-to-left order, in accordance with DR 1227. DR 1227 PR c++/96560 gcc/cp/ChangeLog: * pt.c (tsubst_arg_types): Rearrange so that we substitute into TYPE_ARG_TYPES in forward order while short circuiting appropriately. Adjust formatting. gcc/testsuite/ChangeLog: * g++.dg/template/sfinae-dr1227.C: New test. --- gcc/cp/pt.c | 115 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 60 insertions(+), 55 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b53df9e..141388a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -14946,20 +14946,13 @@ tsubst_arg_types (tree arg_types, tsubst_flags_t complain, tree in_decl) { - tree remaining_arg_types; tree type = NULL_TREE; - int i = 1; + int len = 1; tree expanded_args = NULL_TREE; - tree default_arg; if (!arg_types || arg_types == void_list_node || arg_types == end) return arg_types; - remaining_arg_types = tsubst_arg_types (TREE_CHAIN (arg_types), - args, end, complain, in_decl); - if (remaining_arg_types == error_mark_node) - return error_mark_node; - if (PACK_EXPANSION_P (TREE_VALUE (arg_types))) { /* For a pack expansion, perform substitution on the @@ -14970,7 +14963,7 @@ tsubst_arg_types (tree arg_types, if (TREE_CODE (expanded_args) == TREE_VEC) /* So that we'll spin through the parameters, one by one. */ - i = TREE_VEC_LENGTH (expanded_args); + len = TREE_VEC_LENGTH (expanded_args); else { /* We only partially substituted into the parameter @@ -14979,59 +14972,71 @@ tsubst_arg_types (tree arg_types, expanded_args = NULL_TREE; } } + else + type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl); - while (i > 0) { - --i; - - if (expanded_args) - type = TREE_VEC_ELT (expanded_args, i); - else if (!type) - type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl); + /* Check if a substituted type is erroneous before substituting into + the rest of the chain. */ + for (int i = 0; i < len; i++) + { + if (expanded_args) + type = TREE_VEC_ELT (expanded_args, i); - if (type == error_mark_node) - return error_mark_node; - if (VOID_TYPE_P (type)) - { - if (complain & tf_error) - { - error ("invalid parameter type %qT", type); - if (in_decl) - error ("in declaration %q+D", in_decl); - } - return error_mark_node; + if (type == error_mark_node) + return error_mark_node; + if (VOID_TYPE_P (type)) + { + if (complain & tf_error) + { + error ("invalid parameter type %qT", type); + if (in_decl) + error ("in declaration %q+D", in_decl); + } + return error_mark_node; + } } - /* Do array-to-pointer, function-to-pointer conversion, and ignore - top-level qualifiers as required. */ - type = cv_unqualified (type_decays_to (type)); + /* We do not substitute into default arguments here. The standard + mandates that they be instantiated only when needed, which is + done in build_over_call. */ + tree default_arg = TREE_PURPOSE (arg_types); - /* We do not substitute into default arguments here. The standard - mandates that they be instantiated only when needed, which is - done in build_over_call. */ - default_arg = TREE_PURPOSE (arg_types); + /* Except that we do substitute default arguments under tsubst_lambda_expr, + since the new op() won't have any associated template arguments for us + to refer to later. */ + if (lambda_fn_in_template_p (in_decl)) + default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl, + false/*fn*/, false/*constexpr*/); - /* Except that we do substitute default arguments under tsubst_lambda_expr, - since the new op() won't have any associated template arguments for us - to refer to later. */ - if (lambda_fn_in_template_p (in_decl)) - default_arg = tsubst_copy_and_build (default_arg, args, complain, in_decl, - false/*fn*/, false/*constexpr*/); + tree remaining_arg_types = tsubst_arg_types (TREE_CHAIN (arg_types), + args, end, complain, in_decl); + if (remaining_arg_types == error_mark_node) + return error_mark_node; - if (default_arg && TREE_CODE (default_arg) == DEFERRED_PARSE) - { - /* We've instantiated a template before its default arguments - have been parsed. This can happen for a nested template - class, and is not an error unless we require the default - argument in a call of this function. */ - remaining_arg_types = - tree_cons (default_arg, type, remaining_arg_types); - vec_safe_push (DEFPARSE_INSTANTIATIONS (default_arg), - remaining_arg_types); - } - else - remaining_arg_types = - hash_tree_cons (default_arg, type, remaining_arg_types); - } + for (int i = len-1; i >= 0; i--) + { + if (expanded_args) + type = TREE_VEC_ELT (expanded_args, i); + + /* Do array-to-pointer, function-to-pointer conversion, and ignore + top-level qualifiers as required. */ + type = cv_unqualified (type_decays_to (type)); + + if (default_arg && TREE_CODE (default_arg) == DEFERRED_PARSE) + { + /* We've instantiated a template before its default arguments + have been parsed. This can happen for a nested template + class, and is not an error unless we require the default + argument in a call of this function. */ + remaining_arg_types + = tree_cons (default_arg, type, remaining_arg_types); + vec_safe_push (DEFPARSE_INSTANTIATIONS (default_arg), + remaining_arg_types); + } + else + remaining_arg_types + = hash_tree_cons (default_arg, type, remaining_arg_types); + } return remaining_arg_types; } -- cgit v1.1 From f16f65f8364b5bf23c72a8fdbba4974ecadc5cb6 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 12 Jun 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ee5ef36..183dcf3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,41 @@ +2021-06-11 Patrick Palka + + DR 1227 + PR c++/96560 + * pt.c (tsubst_arg_types): Rearrange so that we substitute into + TYPE_ARG_TYPES in forward order while short circuiting + appropriately. Adjust formatting. + +2021-06-11 Jakub Jelinek + + PR c++/100974 + * cp-tree.h (struct saved_scope): Add consteval_if_p + member. Formatting fix for the discarded_stmt comment. + (in_consteval_if_p, IF_STMT_CONSTEVAL_P): Define. + * parser.c (cp_parser_lambda_expression): Temporarily disable + in_consteval_if_p when parsing lambda body. + (cp_parser_selection_statement): Parse consteval if. + * decl.c (struct named_label_entry): Add in_consteval_if member. + (level_for_consteval_if): New function. + (poplevel_named_label_1, check_previous_goto_1, check_goto): Handle + consteval if. + * constexpr.c (cxx_eval_builtin_function_call): Clarify in comment + why CP_BUILT_IN_IS_CONSTANT_EVALUATED needs to *non_constant_p + for !ctx->manifestly_const_eval. + (cxx_eval_conditional_expression): For IF_STMT_CONSTEVAL_P evaluate + condition as if it was __builtin_is_constant_evaluated call. + (potential_constant_expression_1): For IF_STMT_CONSTEVAL_P always + recurse on both branches. + * cp-gimplify.c (genericize_if_stmt): Genericize IF_STMT_CONSTEVAL_P + as the else branch. + * pt.c (tsubst_expr) : Copy IF_STMT_CONSTEVAL_P. + Temporarily set in_consteval_if_p when recursing on + IF_STMT_CONSTEVAL_P then branch. + (tsubst_lambda_expr): Temporarily disable + in_consteval_if_p when instantiating lambda body. + * call.c (immediate_invocation_p): Return false when + in_consteval_if_p. + 2021-06-11 Marek Polacek PR c++/100995 -- cgit v1.1 From c4e50e500da7692aad53a4488aff32e056149b3c Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 9 Jun 2021 17:48:14 -0400 Subject: c++: speed up looking up the current class While looking at template instantiation tracing, I noticed that we were frequently looking up a particular class template instance while instantiating it. This patch shortcuts that lookup, and speeds up compiling stdc++.h with my (checking/unoptimized) compiler by about 3%. gcc/cp/ChangeLog: * pt.c (lookup_template_class_1): Shortcut current_class_type. --- gcc/cp/pt.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 141388a..d4bb5cc 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9833,6 +9833,13 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, /* From here on, we're only interested in the most general template. */ + /* Shortcut looking up the current class scope again. */ + if (current_class_type) + if (tree ti = CLASSTYPE_TEMPLATE_INFO (current_class_type)) + if (gen_tmpl == most_general_template (TI_TEMPLATE (ti)) + && comp_template_args (arglist, TI_ARGS (ti))) + return current_class_type; + /* Calculate the BOUND_ARGS. These will be the args that are actually tsubst'd into the definition to create the instantiation. */ -- cgit v1.1 From 08e1ff9d6e5a419d5b4a60c077df549e81601d9b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 11 Jun 2021 16:55:30 -0400 Subject: c++: constexpr and array[0] [PR101029] build_vec_init_elt exits early if we're initializing a zero-element array, so build_vec_init needs to do the same to avoid trying to instantiate things after we've already started throwing important bits away. PR c++/101029 gcc/cp/ChangeLog: * init.c (build_vec_init): Shortcut [0] case. gcc/testsuite/ChangeLog: * g++.dg/ext/array4.C: New test. --- gcc/cp/init.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 1b161d5..622d6e9 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -4222,6 +4222,14 @@ build_vec_init (tree base, tree maxindex, tree init, else ptype = atype; + if (integer_all_onesp (maxindex)) + { + /* Shortcut zero element case to avoid unneeded constructor synthesis. */ + if (init && TREE_SIDE_EFFECTS (init)) + base = build2 (COMPOUND_EXPR, void_type_node, init, base); + return base; + } + /* The code we are generating looks like: ({ T* t1 = (T*) base; -- cgit v1.1 From 8b8c391279fd3d85286b918c45171b825b44b74c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 13 Jun 2021 00:16:35 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 183dcf3..c57a901 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2021-06-12 Jason Merrill + + PR c++/101029 + * init.c (build_vec_init): Shortcut [0] case. + +2021-06-12 Jason Merrill + + * pt.c (lookup_template_class_1): Shortcut current_class_type. + 2021-06-11 Patrick Palka DR 1227 -- cgit v1.1 From 3f207ab314c071c6060c7c9a429fcf29fd87b594 Mon Sep 17 00:00:00 2001 From: Trevor Saunders Date: Fri, 11 Jun 2021 23:49:22 -0400 Subject: use range based for loops to iterate over vec<> This changes users of FOR_EACH_VEC_ELT to use range based for loops, where the index variables are otherwise unused. As such the index variables are all deleted, producing shorter and simpler code. Signed-off-by: Trevor Saunders gcc/analyzer/ChangeLog: * call-string.cc (call_string::call_string): Use range based for to iterate over vec<>. (call_string::to_json): Likewise. (call_string::hash): Likewise. (call_string::calc_recursion_depth): Likewise. * checker-path.cc (checker_path::fixup_locations): Likewise. * constraint-manager.cc (equiv_class::equiv_class): Likewise. (equiv_class::to_json): Likewise. (equiv_class::hash): Likewise. (constraint_manager::to_json): Likewise. * engine.cc (impl_region_model_context::on_svalue_leak): Likewise. (on_liveness_change): Likewise. (impl_region_model_context::on_unknown_change): Likewise. * program-state.cc (sm_state_map::set_state): Likewise. * region-model.cc (test_canonicalization_4): Likewise. gcc/ChangeLog: * attribs.c (find_attribute_namespace): Iterate over vec<> with range based for. * auto-profile.c (afdo_find_equiv_class): Likewise. * gcc.c (do_specs_vec): Likewise. (do_spec_1): Likewise. (driver::set_up_specs): Likewise. * gimple-loop-jam.c (any_access_function_variant_p): Likewise. * gimple-ssa-store-merging.c (compatible_load_p): Likewise. (imm_store_chain_info::try_coalesce_bswap): Likewise. (imm_store_chain_info::coalesce_immediate_stores): Likewise. (get_location_for_stmts): Likewise. * graphite-poly.c (print_iteration_domains): Likewise. (free_poly_bb): Likewise. (remove_gbbs_in_scop): Likewise. (free_scop): Likewise. (dump_gbb_cases): Likewise. (dump_gbb_conditions): Likewise. (print_pdrs): Likewise. (print_scop): Likewise. * ifcvt.c (cond_move_process_if_block): Likewise. * lower-subreg.c (decompose_multiword_subregs): Likewise. * regcprop.c (pass_cprop_hardreg::execute): Likewise. * sanopt.c (sanitize_rewrite_addressable_params): Likewise. * sel-sched-dump.c (dump_insn_vector): Likewise. * store-motion.c (store_ops_ok): Likewise. (store_killed_in_insn): Likewise. * timevar.c (timer::named_items::print): Likewise. * tree-cfgcleanup.c (cleanup_control_flow_pre): Likewise. (cleanup_tree_cfg_noloop): Likewise. * tree-data-ref.c (dump_data_references): Likewise. (print_dir_vectors): Likewise. (print_dist_vectors): Likewise. (dump_data_dependence_relations): Likewise. (dump_dist_dir_vectors): Likewise. (dump_ddrs): Likewise. (create_runtime_alias_checks): Likewise. (free_subscripts): Likewise. (save_dist_v): Likewise. (save_dir_v): Likewise. (invariant_access_functions): Likewise. (same_access_functions): Likewise. (access_functions_are_affine_or_constant_p): Likewise. (find_data_references_in_stmt): Likewise. (graphite_find_data_references_in_stmt): Likewise. (free_dependence_relations): Likewise. (free_data_refs): Likewise. * tree-inline.c (copy_debug_stmts): Likewise. * tree-into-ssa.c (dump_currdefs): Likewise. (rewrite_update_phi_arguments): Likewise. * tree-ssa-propagate.c (clean_up_loop_closed_phi): Likewise. * tree-vect-data-refs.c (vect_analyze_possibly_independent_ddr): Likewise. (vect_slp_analyze_node_dependences): Likewise. (vect_slp_analyze_instance_dependence): Likewise. (vect_record_base_alignments): Likewise. (vect_get_peeling_costs_all_drs): Likewise. (vect_peeling_supportable): Likewise. * tree-vectorizer.c (vec_info::~vec_info): Likewise. (vec_info::free_stmt_vec_infos): Likewise. gcc/cp/ChangeLog: * constexpr.c (cxx_eval_call_expression): Iterate over vec<> with range based for. (cxx_eval_store_expression): Likewise. (cxx_eval_loop_expr): Likewise. * decl.c (wrapup_namespace_globals): Likewise. (cp_finish_decl): Likewise. (cxx_simulate_enum_decl): Likewise. * parser.c (cp_parser_postfix_expression): Likewise. --- gcc/cp/constexpr.c | 20 +++++--------------- gcc/cp/decl.c | 15 +++++---------- gcc/cp/parser.c | 4 +--- 3 files changed, 11 insertions(+), 28 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 4f1c3d6..a26aead 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -2793,9 +2793,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, /* Forget the saved values of the callee's SAVE_EXPRs and TARGET_EXPRs. */ - unsigned int i; - tree save_expr; - FOR_EACH_VEC_ELT (save_exprs, i, save_expr) + for (tree save_expr : save_exprs) ctx->global->values.remove (save_expr); /* Remove the parms/result from the values map. Is it worth @@ -5495,9 +5493,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, semantics are not applied on an object under construction. They come into effect when the constructor for the most derived object ends." */ - tree elt; - unsigned int i; - FOR_EACH_VEC_ELT (*ctors, i, elt) + for (tree elt : *ctors) if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (const_object_being_modified), TREE_TYPE (elt))) { @@ -5605,12 +5601,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, /* Update TREE_CONSTANT and TREE_SIDE_EFFECTS on enclosing CONSTRUCTORs, if any. */ - tree elt; - unsigned i; bool c = TREE_CONSTANT (init); bool s = TREE_SIDE_EFFECTS (init); if (!c || s || activated_union_member_p) - FOR_EACH_VEC_ELT (*ctors, i, elt) + for (tree elt : *ctors) { if (!c) TREE_CONSTANT (elt) = false; @@ -5928,9 +5922,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, } /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */ - unsigned int i; - tree save_expr; - FOR_EACH_VEC_ELT (save_exprs, i, save_expr) + for (tree save_expr : save_exprs) ctx->global->values.remove (save_expr); save_exprs.truncate (0); @@ -5952,9 +5944,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, && !*non_constant_p); /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */ - unsigned int i; - tree save_expr; - FOR_EACH_VEC_ELT (save_exprs, i, save_expr) + for (tree save_expr : save_exprs) ctx->global->values.remove (save_expr); return NULL_TREE; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index da254d8..f5596b6 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -841,9 +841,7 @@ wrapup_namespace_globals () { if (vec *statics = static_decls) { - tree decl; - unsigned int i; - FOR_EACH_VEC_ELT (*statics, i, decl) + for (tree decl : *statics) { if (warn_unused_function && TREE_CODE (decl) == FUNCTION_DECL @@ -8260,8 +8258,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, reference, insert it in the statement-tree now. */ if (cleanups) { - unsigned i; tree t; - FOR_EACH_VEC_ELT (*cleanups, i, t) + for (tree t : *cleanups) push_cleanup (decl, t, false); release_tree_vector (cleanups); } @@ -16415,11 +16412,9 @@ cxx_simulate_enum_decl (location_t loc, const char *name, SET_OPAQUE_ENUM_P (enumtype, false); DECL_SOURCE_LOCATION (TYPE_NAME (enumtype)) = loc; - string_int_pair *value; - unsigned int i; - FOR_EACH_VEC_ELT (values, i, value) - build_enumerator (get_identifier (value->first), - build_int_cst (integer_type_node, value->second), + for (const string_int_pair &value : values) + build_enumerator (get_identifier (value.first), + build_int_cst (integer_type_node, value.second), enumtype, NULL_TREE, loc); finish_enum_value_list (enumtype); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 686f98b..b5af387 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7299,8 +7299,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, case RID_BUILTIN_LAUNDER: { vec *vec; - unsigned int i; - tree p; cp_lexer_consume_token (parser->lexer); vec = cp_parser_parenthesized_expression_list (parser, non_attr, @@ -7312,7 +7310,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, break; } - FOR_EACH_VEC_ELT (*vec, i, p) + for (tree p : *vec) mark_exp_read (p); switch (keyword) -- cgit v1.1 From 4e70c34e5ce6fefba22015bd4fe0df33a13567d4 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Mon, 14 Jun 2021 00:16:35 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c57a901..43f2650 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2021-06-13 Trevor Saunders + + * constexpr.c (cxx_eval_call_expression): Iterate over vec<> + with range based for. + (cxx_eval_store_expression): Likewise. + (cxx_eval_loop_expr): Likewise. + * decl.c (wrapup_namespace_globals): Likewise. + (cp_finish_decl): Likewise. + (cxx_simulate_enum_decl): Likewise. + * parser.c (cp_parser_postfix_expression): Likewise. + 2021-06-12 Jason Merrill PR c++/101029 -- cgit v1.1 From 12d13cf50fe68c898ee65d71d1ba9cdb3ea07996 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Mon, 14 Jun 2021 16:49:24 +0200 Subject: C/C++: Fix unused set var warning with omp_clause_affinity [PR100913] PR c/100913 gcc/c/ChangeLog: * c-parser.c (c_parser_omp_clause_affinity): No need to set iterator var in the error case. gcc/cp/ChangeLog: * parser.c (cp_parser_omp_clause_affinity): No need to set iterator var in the error case. --- gcc/cp/parser.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b5af387..d57ddc4 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -37928,9 +37928,7 @@ cp_parser_omp_clause_affinity (cp_parser *parser, tree list) if (iterators) { tree block = poplevel (1, 1, 0); - if (iterators == error_mark_node) - iterators = NULL_TREE; - else + if (iterators != error_mark_node) { TREE_VEC_ELT (iterators, 5) = block; for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) -- cgit v1.1 From 8dc48181affa1d03ec8d47e513d1c62bd16da6f3 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 15 Jun 2021 00:16:37 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 43f2650..f5659cf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2021-06-14 Tobias Burnus + + PR c/100913 + * parser.c (cp_parser_omp_clause_affinity): No need to set iterator + var in the error case. + 2021-06-13 Trevor Saunders * constexpr.c (cxx_eval_call_expression): Iterate over vec<> -- cgit v1.1 From ba2eef033e59d80fde35d0cc3acf4d82f7706e60 Mon Sep 17 00:00:00 2001 From: Robin Dapp Date: Tue, 15 Jun 2021 09:06:02 +0200 Subject: c-family: Copy DECL_USER_ALIGN even if DECL_ALIGN is similar. When re-declaring a function with differing attributes DECL_USER_ALIGN is usually not merged/copied when DECL_ALIGN is similar. On s390 this will cause a warning message not to be shown. Similarly, we warned about the wrong alignment when short-circuiting an alignment initialization in common_handle_aligned_attribute (). Fix this by copying DECL_USER_ALIGN even if DECL_ALIGN is similar as well as getting rid of the short-circuited initialization. gcc/c-family/ChangeLog: * c-attribs.c (common_handle_aligned_attribute): Remove short circuit and dead code. gcc/c/ChangeLog: * c-decl.c (merge_decls): Copy DECL_USER_ALIGN if DECL_ALIGN is similar. gcc/cp/ChangeLog: * decl.c (duplicate_decls): Likewise. --- gcc/cp/decl.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index f5596b6..02772e9 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2805,6 +2805,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) SET_DECL_ALIGN (newdecl, DECL_ALIGN (olddecl)); DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl); } + else if (DECL_ALIGN (olddecl) == DECL_ALIGN (newdecl) + && DECL_USER_ALIGN (olddecl) != DECL_USER_ALIGN (newdecl)) + DECL_USER_ALIGN (newdecl) = 1; + DECL_USER_ALIGN (olddecl) = DECL_USER_ALIGN (newdecl); if (DECL_WARN_IF_NOT_ALIGN (olddecl) > DECL_WARN_IF_NOT_ALIGN (newdecl)) -- cgit v1.1 From ede6c3568f383f62df7bf9234212ee80763fdf6b Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 16 Jun 2021 00:17:05 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f5659cf..3016da8 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,7 @@ +2021-06-15 Robin Dapp + + * decl.c (duplicate_decls): Likewise. + 2021-06-14 Tobias Burnus PR c/100913 -- cgit v1.1 From 6816a44dfe1b5fa9414490a18a4aa723b6f38f18 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 16 Jun 2021 16:09:59 -0400 Subject: c++: static memfn from non-dependent base [PR101078] After my patch for PR91706, or before that with the qualified call, tsubst_baselink returned a BASELINK with BASELINK_BINFO indicating a base of a still-dependent derived class. We need to look up the relevant base binfo in the substituted class. PR c++/101078 PR c++/91706 gcc/cp/ChangeLog: * pt.c (tsubst_baselink): Update binfos in non-dependent case. gcc/testsuite/ChangeLog: * g++.dg/template/access39.C: New test. --- gcc/cp/pt.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d4bb5cc..15947b2 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -16249,8 +16249,19 @@ tsubst_baselink (tree baselink, tree object_type, fns = BASELINK_FUNCTIONS (baselink); } else - /* We're going to overwrite pieces below, make a duplicate. */ - baselink = copy_node (baselink); + { + /* We're going to overwrite pieces below, make a duplicate. */ + baselink = copy_node (baselink); + + if (qualifying_scope != BINFO_TYPE (BASELINK_ACCESS_BINFO (baselink))) + { + /* The decl we found was from non-dependent scope, but we still need + to update the binfos for the instantiated qualifying_scope. */ + BASELINK_ACCESS_BINFO (baselink) = TYPE_BINFO (qualifying_scope); + BASELINK_BINFO (baselink) = lookup_base (qualifying_scope, binfo_type, + ba_unique, nullptr, complain); + } + } /* If lookup found a single function, mark it as used at this point. (If lookup found multiple functions the one selected later by -- cgit v1.1 From 9a61dfdb5ecb58bc4caea1c11e017d93bdd1d9a5 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 17 Jun 2021 00:16:54 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3016da8..8d14d38 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2021-06-16 Jason Merrill + + PR c++/101078 + PR c++/91706 + * pt.c (tsubst_baselink): Update binfos in non-dependent case. + 2021-06-15 Robin Dapp * decl.c (duplicate_decls): Likewise. -- cgit v1.1 From ff4deb4b1d0c5947669ddc76fde4db83e28009d8 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 16 Jun 2021 17:42:15 -0400 Subject: c++: Tweak PR101029 fix The case of an initializer with side effects for a zero-length array seems extremely unlikely, but we should still return the right type in that case. PR c++/101029 gcc/cp/ChangeLog: * init.c (build_vec_init): Preserve the type of base. --- gcc/cp/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 622d6e9..4bd942f 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -4226,7 +4226,7 @@ build_vec_init (tree base, tree maxindex, tree init, { /* Shortcut zero element case to avoid unneeded constructor synthesis. */ if (init && TREE_SIDE_EFFECTS (init)) - base = build2 (COMPOUND_EXPR, void_type_node, init, base); + base = build2 (COMPOUND_EXPR, ptype, init, base); return base; } -- cgit v1.1 From 331e20a69be0d9e7d448580945945d4c7a1e3c0a Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 17 Jun 2021 15:31:15 -0400 Subject: c++: deleted after first declaration [PR101106] An explicitly deleted function must be deleted on its first declaration. We were diagnosing this error only with -Wpedantic, but always giving the "previous declaration" note. This patch removes the -Wpedantic dependency and also makes the note depend on the previous diagnostic. PR c++/101106 gcc/cp/ChangeLog: * decl.c (duplicate_decls): Make 'deleted after first declaration' pedwarn on by default. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/deleted15.C: New test. --- gcc/cp/decl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 02772e9..66bcc4b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2170,11 +2170,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (DECL_DELETED_FN (newdecl)) { auto_diagnostic_group d; - pedwarn (newdecl_loc, OPT_Wpedantic, - "deleted definition of %qD is not first declaration", - newdecl); - inform (olddecl_loc, - "previous declaration of %qD", olddecl); + if (pedwarn (newdecl_loc, 0, "deleted definition of %qD " + "is not first declaration", newdecl)) + inform (olddecl_loc, + "previous declaration of %qD", olddecl); } DECL_DELETED_FN (newdecl) |= DECL_DELETED_FN (olddecl); } -- cgit v1.1 From 688359a27d835bbdab554fdf5eb207f1bd678371 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 18 Jun 2021 00:16:58 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8d14d38..5142210 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2021-06-17 Jason Merrill + + PR c++/101106 + * decl.c (duplicate_decls): Make 'deleted after first declaration' + pedwarn on by default. + +2021-06-17 Jason Merrill + + PR c++/101029 + * init.c (build_vec_init): Preserve the type of base. + 2021-06-16 Jason Merrill PR c++/101078 -- cgit v1.1 From 644c2cc5f2c09506a7bfef293a7f90efa8d7e5fa Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 21 Jun 2021 13:30:42 +0200 Subject: inline-asm: Fix ICE with bitfields in "m" operands [PR100785] Bitfields, while they live in memory, aren't something inline-asm can easily operate on. For C and "=m" or "+m", we were diagnosing bitfields in the past in the FE, where c_mark_addressable had: case COMPONENT_REF: if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1))) { error ("cannot take address of bit-field %qD", TREE_OPERAND (x, 1)); return false; } but that check got moved in GCC 6 to build_unary_op instead and now we emit an error during expansion and ICE afterwards (i.e. error-recovery). For "m" it used to be diagnosed in c_mark_addressable too, but since GCC 6 it is ice-on-invalid. For C++, this was never diagnosed in the FE, but used to be diagnosed in the gimplifier and/or during expansion before 4.8. The following patch does multiple things: 1) diagnoses it in the FEs 2) stops emitting a redundant diagnostic in the gimplifier using the usual way, if we already see error_mark_node, we assume error has been emitted already and only diagnose if it wasn't error_mark_node; this helps diagnosing the same bug with multiple different errors 3) simplifies during expansion the inline asm if any errors have been reported (similarly how e.g. vregs pass if it detects errors on inline-asm either deletes them or simplifies to bare minimum - just labels), so that we don't have error-recovery ICEs there 2021-06-11 Jakub Jelinek PR inline-asm/100785 gcc/ * gimplify.c (gimplify_asm_expr): Don't diagnose errors if output or input operands were already error_mark_node. * cfgexpand.c (expand_asm_stmt): If errors are emitted, remove all inputs, outputs and clobbers from the asm and set template to "". gcc/c/ * c-typeck.c (c_mark_addressable): Diagnose trying to make bit-fields addressable. gcc/cp/ * typeck.c (cxx_mark_addressable): Diagnose trying to make bit-fields addressable. gcc/testsuite/ * c-c++-common/pr100785.c: New test. * gcc.dg/pr48552-1.c: Don't expect invalid lvalue errors. * gcc.dg/pr48552-2.c: Likewise. --- gcc/cp/typeck.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index dbb2370..5a9331b 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -7119,9 +7119,14 @@ cxx_mark_addressable (tree exp, bool array_ref_p) && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0)))) return true; + x = TREE_OPERAND (x, 0); + break; + + case COMPONENT_REF: + if (bitfield_p (x)) + error ("attempt to take address of bit-field"); /* FALLTHRU */ case ADDR_EXPR: - case COMPONENT_REF: case ARRAY_REF: case REALPART_EXPR: case IMAGPART_EXPR: -- cgit v1.1 From de31f5445b12fd9ab9969dc536d821fe6f0edad0 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 21 Jun 2021 07:54:26 -0400 Subject: c++: conversion to base of vbase in NSDMI [PR80431] The delayed processing of conversions to a virtual base in an NSDMI assumes the target base type is a (possibly indirect) virtual base of the current class, but the target base type could also be a base of a virtual base, as in the testcase below. Since such a base isn't a part of CLASSTYPE_VBASECLASSES, we end up miscompiling the testcase due to the call to build_base_path (with binfo=NULL_TREE) silently returning error_mark_node. Fix this by using convert_to_base to build the conversion instead. PR c++/80431 gcc/cp/ChangeLog: * tree.c (bot_replace): Use convert_to_base to build the conversion to the (morally) virtual base. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/nsdmi-virtual1a.C: New test. --- gcc/cp/tree.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index fec5afa..297da2b 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3242,15 +3242,11 @@ bot_replace (tree* t, int* /*walk_subtrees*/, void* data_) else if (TREE_CODE (*t) == CONVERT_EXPR && CONVERT_EXPR_VBASE_PATH (*t)) { - /* In an NSDMI build_base_path defers building conversions to virtual - bases, and we handle it here. */ - tree basetype = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (*t))); - vec *vbases = CLASSTYPE_VBASECLASSES (current_class_type); - int i; tree binfo; - FOR_EACH_VEC_SAFE_ELT (vbases, i, binfo) - if (BINFO_TYPE (binfo) == basetype) - break; - *t = build_base_path (PLUS_EXPR, TREE_OPERAND (*t, 0), binfo, true, + /* In an NSDMI build_base_path defers building conversions to morally + virtual bases, and we handle it here. */ + tree basetype = TREE_TYPE (*t); + *t = convert_to_base (TREE_OPERAND (*t, 0), basetype, + /*check_access=*/false, /*nonnull=*/true, tf_warning_or_error); } -- cgit v1.1 From 21761d2b2b01f6cef4287c646845f6b3006546aa Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 21 Jun 2021 07:54:29 -0400 Subject: c++: REF_PARENTHESIZED_P wrapper inhibiting NRVO [PR67302] Here, in C++14 or later, we remember the parentheses around 'a' in the return statement by using a REF_PARENTHESIZED_P wrapper, which ends up inhibiting NRVO because we don't look through this wrapper before checking the conditions for NRVO. This patch fixes this by calling maybe_undo_parenthesized_ref sooner in check_return_expr. PR c++/67302 gcc/cp/ChangeLog: * typeck.c (check_return_expr): Call maybe_undo_parenthesized_ref sooner, before the NRVO handling. gcc/testsuite/ChangeLog: * g++.dg/opt/nrv21.C: New test. --- gcc/cp/typeck.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 5a9331b..937581a 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -10311,7 +10311,10 @@ check_return_expr (tree retval, bool *no_warning) See finish_function and finalize_nrv for the rest of this optimization. */ if (retval) - STRIP_ANY_LOCATION_WRAPPER (retval); + { + retval = maybe_undo_parenthesized_ref (retval); + STRIP_ANY_LOCATION_WRAPPER (retval); + } bool named_return_value_okay_p = can_do_nrvo_p (retval, functype); if (fn_returns_value_p && flag_elide_constructors) @@ -10345,10 +10348,6 @@ check_return_expr (tree retval, bool *no_warning) if (VOID_TYPE_P (functype)) return error_mark_node; - /* If we had an id-expression obfuscated by force_paren_expr, we need - to undo it so we can try to treat it as an rvalue below. */ - retval = maybe_undo_parenthesized_ref (retval); - if (processing_template_decl) retval = build_non_dependent_expr (retval); -- cgit v1.1 From 2f080224cfa9de0e215324c6ac242d6ee3f27172 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 22 Jun 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5142210..cfe9aa4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2021-06-21 Patrick Palka + + PR c++/67302 + * typeck.c (check_return_expr): Call maybe_undo_parenthesized_ref + sooner, before the NRVO handling. + +2021-06-21 Patrick Palka + + PR c++/80431 + * tree.c (bot_replace): Use convert_to_base to build the + conversion to the (morally) virtual base. + +2021-06-21 Jakub Jelinek + + PR inline-asm/100785 + * typeck.c (cxx_mark_addressable): Diagnose trying to make + bit-fields addressable. + 2021-06-17 Jason Merrill PR c++/101106 -- cgit v1.1 From 3eecc1db4c691a87ef4a229d059aa863066d9a1c Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 23 Jun 2021 08:24:34 -0400 Subject: c++: CTAD and deduction guide selection [PR86439] During CTAD, we select the best viable deduction guide using build_new_function_call, which performs overload resolution on the set of candidate guides and then forms a call to the guide. As the PR points out, this latter step is unnecessary and occasionally incorrect since a call to the selected guide may be ill-formed, or forming the call may have side effects such as prematurely deducing the type of a {}. So this patch introduces a specialized subroutine based on build_new_function_call that stops short of building a call to the selected function, and makes do_class_deduction use this subroutine instead. And since a call is no longer built, do_class_deduction doesn't need to set tf_decltype or cp_unevaluated_operand anymore. This change causes us to reject some container CTAD examples in the libstdc++ testsuite due to deduction failure for {}, which AFAICT is the correct behavior. Previously in e.g. the first removed example std::map{{std::pair{1, 2.0}, {2, 3.0}, {3, 4.0}}, {}}, the type of the {} would get deduced to less as a side effect of forming a call to the chosen guide template, typename _Allocator = allocator>> map(initializer_list>, _Compare = _Compare(), _Allocator = _Allocator()) -> map<_Key, _Tp, _Compare, _Allocator>; which made later overload resolution for the constructor call unambiguous. Now, the type of the {} remains undeduced until constructor overload resolution, and we complain about ambiguity for the two equally good constructor candidates map(initializer_list, const _Compare& = _Compare(), const allocator_type& = allocator_type()) map(initializer_list, const allocator_type&). This patch fixes these problematic container CTAD examples by giving the {} an appropriate concrete type. Two of these adjusted CTAD examples (one for std::set and one for std::multiset) end up triggering an unrelated CTAD bug on trunk, PR101174, so these two adjusted examples are commented out for now. PR c++/86439 gcc/cp/ChangeLog: * call.c (print_error_for_call_failure): Constify 'args' parameter. (perform_dguide_overload_resolution): Define. * cp-tree.h: (perform_dguide_overload_resolution): Declare. * pt.c (do_class_deduction): Use perform_dguide_overload_resolution instead of build_new_function_call. Don't use tf_decltype or set cp_unevaluated_operand. Remove unnecessary NULL_TREE tests. libstdc++-v3/ChangeLog: * testsuite/23_containers/map/cons/deduction.cc: Replace ambiguous CTAD examples. * testsuite/23_containers/multimap/cons/deduction.cc: Likewise. * testsuite/23_containers/multiset/cons/deduction.cc: Likewise. Mention one of the replaced examples is broken due to PR101174. * testsuite/23_containers/set/cons/deduction.cc: Likewise. * testsuite/23_containers/unordered_map/cons/deduction.cc: Replace ambiguous CTAD examples. * testsuite/23_containers/unordered_multimap/cons/deduction.cc: Likewise. * testsuite/23_containers/unordered_multiset/cons/deduction.cc: Likewise. * testsuite/23_containers/unordered_set/cons/deduction.cc: Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction88.C: New test. * g++.dg/cpp1z/class-deduction89.C: New test. * g++.dg/cpp1z/class-deduction90.C: New test. --- gcc/cp/call.c | 36 +++++++++++++++++++++++++++++++++++- gcc/cp/cp-tree.h | 2 ++ gcc/cp/pt.c | 41 ++++++++++++++--------------------------- 3 files changed, 51 insertions(+), 28 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 9f03534..aafc7ac 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4629,7 +4629,7 @@ perform_overload_resolution (tree fn, functions. */ static void -print_error_for_call_failure (tree fn, vec *args, +print_error_for_call_failure (tree fn, const vec *args, struct z_candidate *candidates) { tree targs = NULL_TREE; @@ -4654,6 +4654,40 @@ print_error_for_call_failure (tree fn, vec *args, print_z_candidates (loc, candidates); } +/* Perform overload resolution on the set of deduction guides DGUIDES + using ARGS. Returns the selected deduction guide, or error_mark_node + if overload resolution fails. */ + +tree +perform_dguide_overload_resolution (tree dguides, const vec *args, + tsubst_flags_t complain) +{ + z_candidate *candidates; + bool any_viable_p; + tree result; + + gcc_assert (deduction_guide_p (OVL_FIRST (dguides))); + + /* Get the high-water mark for the CONVERSION_OBSTACK. */ + void *p = conversion_obstack_alloc (0); + + z_candidate *cand = perform_overload_resolution (dguides, args, &candidates, + &any_viable_p, complain); + if (!cand) + { + if (complain & tf_error) + print_error_for_call_failure (dguides, args, candidates); + result = error_mark_node; + } + else + result = cand->fn; + + /* Free all the conversions we allocated. */ + obstack_free (&conversion_obstack, p); + + return result; +} + /* Return an expression for a call to FN (a namespace-scope function, or a static member function) with the ARGS. This may change ARGS. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 36f99cc..6f71371 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6437,6 +6437,8 @@ extern void complain_about_bad_argument (location_t arg_loc, tree from_type, tree to_type, tree fndecl, int parmnum); extern void maybe_inform_about_fndecl_for_bogus_argument_init (tree, int); +extern tree perform_dguide_overload_resolution (tree, const vec *, + tsubst_flags_t); /* A class for recording information about access failures (e.g. private diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 15947b2..732fb40 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -29382,7 +29382,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, if (tree guide = maybe_aggr_guide (tmpl, init, args)) cands = lookup_add (guide, cands); - tree call = error_mark_node; + tree fndecl = error_mark_node; /* If this is list-initialization and the class has a list constructor, first try deducing from the list as a single argument, as [over.match.list]. */ @@ -29396,11 +29396,9 @@ do_class_deduction (tree ptype, tree tmpl, tree init, } if (list_cands) { - ++cp_unevaluated_operand; - call = build_new_function_call (list_cands, &args, tf_decltype); - --cp_unevaluated_operand; + fndecl = perform_dguide_overload_resolution (list_cands, args, tf_none); - if (call == error_mark_node) + if (fndecl == error_mark_node) { /* That didn't work, now try treating the list as a sequence of arguments. */ @@ -29416,31 +29414,22 @@ do_class_deduction (tree ptype, tree tmpl, tree init, "user-declared constructors", type); return error_mark_node; } - else if (!cands && call == error_mark_node) + else if (!cands && fndecl == error_mark_node) { error ("cannot deduce template arguments of %qT, as it has no viable " "deduction guides", type); return error_mark_node; } - if (call == error_mark_node) - { - ++cp_unevaluated_operand; - call = build_new_function_call (cands, &args, tf_decltype); - --cp_unevaluated_operand; - } + if (fndecl == error_mark_node) + fndecl = perform_dguide_overload_resolution (cands, args, tf_none); - if (call == error_mark_node) + if (fndecl == error_mark_node) { if (complain & tf_warning_or_error) { error ("class template argument deduction failed:"); - - ++cp_unevaluated_operand; - call = build_new_function_call (cands, &args, - complain | tf_decltype); - --cp_unevaluated_operand; - + perform_dguide_overload_resolution (cands, args, complain); if (elided) inform (input_location, "explicit deduction guides not considered " "for copy-initialization"); @@ -29451,8 +29440,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, constructor is chosen, the initialization is ill-formed. */ else if (flags & LOOKUP_ONLYCONVERTING) { - tree fndecl = cp_get_callee_fndecl_nofold (call); - if (fndecl && DECL_NONCONVERTING_P (fndecl)) + if (DECL_NONCONVERTING_P (fndecl)) { if (complain & tf_warning_or_error) { @@ -29470,12 +29458,10 @@ do_class_deduction (tree ptype, tree tmpl, tree init, /* If CTAD succeeded but the type doesn't have any explicit deduction guides, this deduction might not be what the user intended. */ - if (call != error_mark_node && !any_dguides_p) + if (fndecl != error_mark_node && !any_dguides_p) { - tree fndecl = cp_get_callee_fndecl_nofold (call); - if (fndecl != NULL_TREE - && (!DECL_IN_SYSTEM_HEADER (fndecl) - || global_dc->dc_warn_system_headers) + if ((!DECL_IN_SYSTEM_HEADER (fndecl) + || global_dc->dc_warn_system_headers) && warning (OPT_Wctad_maybe_unsupported, "%qT may not intend to support class template argument " "deduction", type)) @@ -29483,7 +29469,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init, "warning"); } - return cp_build_qualified_type (TREE_TYPE (call), cp_type_quals (ptype)); + return cp_build_qualified_type (TREE_TYPE (TREE_TYPE (fndecl)), + cp_type_quals (ptype)); } /* Replace occurrences of 'auto' in TYPE with the appropriate type deduced -- cgit v1.1 From 7da4eae3dcef6fd5d955eb2c80c453aa52368004 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 23 Jun 2021 17:23:39 -0400 Subject: c++: excessive instantiation during CTAD [PR101174] We set DECL_CONTEXT on implicitly generated deduction guides so that their access is consistent with that of the constructor. But this apparently leads to excessive instantiation in some cases, ultimately because instantiation of a deduction guide should be independent of instantiation of the resulting class specialization, but setting the DECL_CONTEXT of the former to the latter breaks this independence. To fix this, this patch makes push_access_scope handle artificial deduction guides specifically rather than setting their DECL_CONTEXT in build_deduction_guide. We could alternatively make the class befriend the guide via DECL_BEFRIENDING_CLASSES, but that wouldn't be a complete fix and would break class-deduction-access3.C below since friendship isn't transitive. PR c++/101174 gcc/cp/ChangeLog: * pt.c (push_access_scope): For artificial deduction guides, set the access scope to that of the constructor. (pop_access_scope): Likewise. (build_deduction_guide): Don't set DECL_CONTEXT on the guide. libstdc++-v3/ChangeLog: * testsuite/23_containers/multiset/cons/deduction.cc: Uncomment CTAD example that was rejected by this bug. * testsuite/23_containers/set/cons/deduction.cc: Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction-access3.C: New test. * g++.dg/cpp1z/class-deduction91.C: New test. --- gcc/cp/pt.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 732fb40..5c55507 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -236,6 +236,10 @@ push_access_scope (tree t) push_nested_class (DECL_FRIEND_CONTEXT (t)); else if (DECL_CLASS_SCOPE_P (t)) push_nested_class (DECL_CONTEXT (t)); + else if (deduction_guide_p (t) && DECL_ARTIFICIAL (t)) + /* An artificial deduction guide should have the same access as + the constructor. */ + push_nested_class (TREE_TYPE (TREE_TYPE (t))); else push_to_top_level (); @@ -255,7 +259,9 @@ pop_access_scope (tree t) if (TREE_CODE (t) == FUNCTION_DECL) current_function_decl = saved_access_scope->pop(); - if (DECL_FRIEND_CONTEXT (t) || DECL_CLASS_SCOPE_P (t)) + if (DECL_FRIEND_CONTEXT (t) + || DECL_CLASS_SCOPE_P (t) + || (deduction_guide_p (t) && DECL_ARTIFICIAL (t))) pop_nested_class (); else pop_from_top_level (); @@ -28804,9 +28810,6 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com DECL_ABSTRACT_ORIGIN (ded_tmpl) = fn_tmpl; if (ci) set_constraints (ded_tmpl, ci); - /* The artificial deduction guide should have same access as the - constructor. */ - DECL_CONTEXT (ded_fn) = type; return ded_tmpl; } -- cgit v1.1 From fcf617f0d2a5a1b624718e07d7b219cb0234436f Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 24 Jun 2021 00:16:30 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index cfe9aa4..368ef75 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2021-06-23 Patrick Palka + + PR c++/101174 + * pt.c (push_access_scope): For artificial deduction guides, + set the access scope to that of the constructor. + (pop_access_scope): Likewise. + (build_deduction_guide): Don't set DECL_CONTEXT on the guide. + +2021-06-23 Patrick Palka + + PR c++/86439 + * call.c (print_error_for_call_failure): Constify 'args' parameter. + (perform_dguide_overload_resolution): Define. + * cp-tree.h: (perform_dguide_overload_resolution): Declare. + * pt.c (do_class_deduction): Use perform_dguide_overload_resolution + instead of build_new_function_call. Don't use tf_decltype or + set cp_unevaluated_operand. Remove unnecessary NULL_TREE tests. + 2021-06-21 Patrick Palka PR c++/67302 -- 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/parser.c | 18 ++++++++- gcc/cp/pt.c | 9 +++-- gcc/cp/semantics.c | 111 ++++++++++++++++++++++++++++++++--------------------- 3 files changed, 90 insertions(+), 48 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d57ddc4..b7a4298 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -40877,7 +40877,9 @@ cp_omp_split_clauses (location_t loc, enum tree_code code, c_omp_split_clauses (loc, code, mask, clauses, cclauses); for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++) if (cclauses[i]) - cclauses[i] = finish_omp_clauses (cclauses[i], C_ORT_OMP); + cclauses[i] = finish_omp_clauses (cclauses[i], + i == C_OMP_CLAUSE_SPLIT_TARGET + ? C_ORT_OMP_TARGET : C_ORT_OMP); } /* OpenMP 5.0: @@ -42219,6 +42221,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)) static bool @@ -42381,7 +42384,18 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, OMP_TARGET_CLAUSES (stmt) = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK, - "#pragma omp target", pragma_tok); + "#pragma omp target", pragma_tok, false); + for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION) + { + tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + OMP_CLAUSE_DECL (nc) = OMP_CLAUSE_DECL (c); + OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_ALWAYS_TOFROM); + OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = nc; + } + OMP_TARGET_CLAUSES (stmt) + = finish_omp_clauses (OMP_TARGET_CLAUSES (stmt), C_ORT_OMP_TARGET); c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true); pc = &OMP_TARGET_CLAUSES (stmt); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5c55507..1af8120 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -18886,9 +18886,12 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case OACC_DATA: case OMP_TARGET_DATA: case OMP_TARGET: - tmp = tsubst_omp_clauses (OMP_CLAUSES (t), (TREE_CODE (t) == OACC_DATA) - ? C_ORT_ACC : C_ORT_OMP, args, complain, - in_decl); + tmp = tsubst_omp_clauses (OMP_CLAUSES (t), + TREE_CODE (t) == OACC_DATA + ? C_ORT_ACC + : TREE_CODE (t) == OMP_TARGET + ? C_ORT_OMP_TARGET : C_ORT_OMP, + args, complain, in_decl); keep_next_level (true); stmt = begin_omp_structured_block (); 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 c06493dc30afbf65b14d783c7cd53f20877ef577 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 24 Jun 2021 11:29:02 -0400 Subject: c++: requires-expression folding [PR101182] Here we're crashing because cp_fold_function walks into the (templated) requirements of a requires-expression outside a template, but the folding routines aren't prepared to handle templated trees. This patch fixes this by making cp_fold use evaluate_requires_expr to fold a requires-expression as a whole, which also means we no longer need to explicitly do so during gimplification. (Note that we delay folding of such requires-expressions for sake of better diagnostics when one is used as the condition of a failed static_assert.) PR c++/101182 gcc/cp/ChangeLog: * constraint.cc (evaluate_requires_expr): Adjust function comment. * cp-gimplify.c (cp_genericize_r) : Move to ... (cp_fold) : ... here. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-requires25.C: New test. --- gcc/cp/constraint.cc | 2 +- gcc/cp/cp-gimplify.c | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 74b16d2..286332b 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3340,7 +3340,7 @@ evaluate_concept_check (tree check) } /* Evaluate the requires-expression T, returning either boolean_true_node - or boolean_false_node. This is used during gimplification and constexpr + or boolean_false_node. This is used during folding and constexpr evaluation. */ tree diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 96d91b6..33e1055 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -1465,12 +1465,6 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) TARGET_EXPR_NO_ELIDE (stmt) = 1; break; - case REQUIRES_EXPR: - /* Emit the value of the requires-expression. */ - *stmt_p = evaluate_requires_expr (stmt); - *walk_subtrees = 0; - break; - case TEMPLATE_ID_EXPR: gcc_assert (concept_check_p (stmt)); /* Emit the value of the concept check. */ @@ -2708,6 +2702,10 @@ cp_fold (tree x) x = r; break; + case REQUIRES_EXPR: + x = evaluate_requires_expr (x); + break; + default: return org_x; } -- cgit v1.1 From c761be53f6b62e22ac5de18c4aaf88648f64f5b7 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 24 Jun 2021 13:11:44 -0400 Subject: c++: alias CTAD and aggregate deduction cand [PR98832] During alias CTAD, we're accidentally ignoring the aggregate deduction candidate for the underlying template because this guide is added separately via maybe_aggr_guide (which doesn't yet handle alias templates) instead of via deduction_guides_for (which does). This patch makes maybe_aggr_guide handle alias templates in a manner similar to deduction_guides_for. PR c++/98832 gcc/cp/ChangeLog: * pt.c (maybe_aggr_guide): Handle alias templates appropriately. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-alias9.C: New test. --- gcc/cp/pt.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1af8120..f73c747 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -28886,6 +28886,8 @@ is_spec_or_derived (tree etype, tree tmpl) return !err; } +static tree alias_ctad_tweaks (tree, tree); + /* Return a C++20 aggregate deduction candidate for TYPE initialized from INIT. */ @@ -28898,6 +28900,15 @@ maybe_aggr_guide (tree tmpl, tree init, vec *args) if (init == NULL_TREE) return NULL_TREE; + if (DECL_ALIAS_TEMPLATE_P (tmpl)) + { + tree under = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl)); + tree tinfo = get_template_info (under); + if (tree guide = maybe_aggr_guide (TI_TEMPLATE (tinfo), init, args)) + return alias_ctad_tweaks (tmpl, guide); + return NULL_TREE; + } + /* We might be creating a guide for a class member template, e.g., template struct A { -- cgit v1.1 From 9aa8327e86eba9a5ad6dacb4db505e3451854976 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 25 Jun 2021 00:16:53 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 368ef75..770d327 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,33 @@ +2021-06-24 Patrick Palka + + PR c++/98832 + * pt.c (maybe_aggr_guide): Handle alias templates appropriately. + +2021-06-24 Patrick Palka + + PR c++/101182 + * constraint.cc (evaluate_requires_expr): Adjust function comment. + * cp-gimplify.c (cp_genericize_r) : Move to ... + (cp_fold) : ... here. + +2021-06-24 Jakub Jelinek + + * 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. + 2021-06-23 Patrick Palka PR c++/101174 -- 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/call.c | 10 +++++----- gcc/cp/class.c | 2 +- gcc/cp/constraint.cc | 4 ++-- gcc/cp/coroutines.cc | 22 +++++++++++----------- gcc/cp/cp-gimplify.c | 20 +++++++++++--------- gcc/cp/cp-ubsan.c | 2 +- gcc/cp/cvt.c | 12 +++++------- gcc/cp/decl.c | 15 ++++++--------- gcc/cp/decl2.c | 4 ++-- gcc/cp/except.c | 3 ++- gcc/cp/init.c | 16 ++++++++-------- gcc/cp/method.c | 2 +- gcc/cp/parser.c | 6 +++++- gcc/cp/pt.c | 23 +++++++++++------------ gcc/cp/rtti.c | 4 ++-- gcc/cp/semantics.c | 17 +++++++++-------- gcc/cp/tree.c | 2 +- gcc/cp/typeck.c | 27 ++++++++++++--------------- 18 files changed, 95 insertions(+), 96 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index aafc7ac..e4df72e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9499,7 +9499,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) { /* Avoid copying empty classes. */ val = build2 (COMPOUND_EXPR, type, arg, to); - TREE_NO_WARNING (val) = 1; + suppress_warning (val, OPT_Wunused); } else if (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (as_base))) { @@ -9530,7 +9530,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) build2 (MEM_REF, array_type, arg0, alias_set), build2 (MEM_REF, array_type, arg, alias_set)); val = build2 (COMPOUND_EXPR, TREE_TYPE (to), t, to); - TREE_NO_WARNING (val) = 1; + suppress_warning (val, OPT_Wunused); } cp_warn_deprecated_use (fn, complain); @@ -9604,7 +9604,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) { tree c = extract_call_expr (call); if (TREE_CODE (c) == CALL_EXPR) - TREE_NO_WARNING (c) = 1; + suppress_warning (c /* Suppress all warnings. */); } if (TREE_CODE (fn) == ADDR_EXPR) { @@ -12554,11 +12554,11 @@ set_up_extended_ref_temp (tree decl, tree expr, vec **cleanups, TREE_ADDRESSABLE (var) = 1; if (TREE_CODE (decl) == FIELD_DECL - && extra_warnings && !TREE_NO_WARNING (decl)) + && extra_warnings && !warning_suppressed_p (decl)) { warning (OPT_Wextra, "a temporary bound to %qD only persists " "until the constructor exits", decl); - TREE_NO_WARNING (decl) = true; + suppress_warning (decl); } /* Recursively extend temps in this initializer. */ diff --git a/gcc/cp/class.c b/gcc/cp/class.c index b53a4db..c89ffad 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -6704,7 +6704,7 @@ layout_class_type (tree t, tree *virtuals_p) laying out an Objective-C class. The ObjC ABI differs from the C++ ABI, and so we do not want a warning here. */ - && !TREE_NO_WARNING (field) + && !warning_suppressed_p (field, OPT_Wabi) && !last_field_was_bitfield && !integer_zerop (size_binop (TRUNC_MOD_EXPR, DECL_FIELD_BIT_OFFSET (field), diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 286332b..6df3ca6 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3290,14 +3290,14 @@ constraint_satisfaction_value (tree t, tree args, sat_info info) else r = satisfy_nondeclaration_constraints (t, args, info); if (r == error_mark_node && info.quiet () - && !(DECL_P (t) && TREE_NO_WARNING (t))) + && !(DECL_P (t) && warning_suppressed_p (t))) { /* Replay the error noisily. */ sat_info noisy (tf_warning_or_error, info.in_decl); constraint_satisfaction_value (t, args, noisy); if (DECL_P (t) && !args) /* Avoid giving these errors again. */ - TREE_NO_WARNING (t) = true; + suppress_warning (t); } return r; } diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 1bf1931..a1b0b31 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1078,7 +1078,7 @@ finish_co_await_expr (location_t kw, tree expr) is declared to return non-void (most likely). This is correct - we synthesize the return for the ramp in the compiler. So suppress any extraneous warnings during substitution. */ - TREE_NO_WARNING (current_function_decl) = true; + suppress_warning (current_function_decl, OPT_Wreturn_type); /* If we don't know the promise type, we can't proceed, build the co_await with the expression unchanged. */ @@ -1154,7 +1154,7 @@ finish_co_yield_expr (location_t kw, tree expr) is declared to return non-void (most likely). This is correct - we synthesize the return for the ramp in the compiler. So suppress any extraneous warnings during substitution. */ - TREE_NO_WARNING (current_function_decl) = true; + suppress_warning (current_function_decl, OPT_Wreturn_type); /* If we don't know the promise type, we can't proceed, build the co_await with the expression unchanged. */ @@ -1235,7 +1235,7 @@ finish_co_return_stmt (location_t kw, tree expr) is declared to return non-void (most likely). This is correct - we synthesize the return for the ramp in the compiler. So suppress any extraneous warnings during substitution. */ - TREE_NO_WARNING (current_function_decl) = true; + suppress_warning (current_function_decl, OPT_Wreturn_type); if (processing_template_decl && check_for_bare_parameter_packs (expr)) @@ -1259,7 +1259,7 @@ finish_co_return_stmt (location_t kw, tree expr) /* Suppress -Wreturn-type for co_return, we need to check indirectly whether the promise type has a suitable return_void/return_value. */ - TREE_NO_WARNING (current_function_decl) = true; + suppress_warning (current_function_decl, OPT_Wreturn_type); if (!processing_template_decl && warn_sequence_point) verify_sequence_points (expr); @@ -2458,7 +2458,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* done. */ r = build_stmt (loc, RETURN_EXPR, NULL); - TREE_NO_WARNING (r) |= 1; /* We don't want a warning about this. */ + suppress_warning (r); /* We don't want a warning about this. */ r = maybe_cleanup_point_expr_void (r); add_stmt (r); @@ -2467,7 +2467,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, add_stmt (r); r = build_stmt (loc, RETURN_EXPR, NULL); - TREE_NO_WARNING (r) |= 1; /* We don't want a warning about this. */ + suppress_warning (r); /* We don't want a warning about this. */ r = maybe_cleanup_point_expr_void (r); add_stmt (r); @@ -4142,7 +4142,7 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, finish_if_stmt_cond (not_iarc, not_iarc_if); /* If the initial await resume called value is false, rethrow... */ tree rethrow = build_throw (fn_start, NULL_TREE); - TREE_NO_WARNING (rethrow) = true; + suppress_warning (rethrow); finish_expr_stmt (rethrow); finish_then_clause (not_iarc_if); tree iarc_scope = IF_SCOPE (not_iarc_if); @@ -4243,7 +4243,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* For early errors, we do not want a diagnostic about the missing ramp return value, since the user cannot fix this - a 'return' is not allowed in a coroutine. */ - TREE_NO_WARNING (orig) = true; + suppress_warning (orig, OPT_Wreturn_type); /* Discard the body, we can't process it further. */ pop_stmt_list (DECL_SAVED_TREE (orig)); DECL_SAVED_TREE (orig) = push_stmt_list (); @@ -4269,7 +4269,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) DECL_SAVED_TREE (orig) = push_stmt_list (); append_to_statement_list (fnbody, &DECL_SAVED_TREE (orig)); /* Suppress warnings about the missing return value. */ - TREE_NO_WARNING (orig) = true; + suppress_warning (orig, OPT_Wreturn_type); return false; } @@ -4948,7 +4948,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) BIND_EXPR_BODY (ramp_bind) = pop_stmt_list (ramp_body); DECL_SAVED_TREE (orig) = newbody; /* Suppress warnings about the missing return value. */ - TREE_NO_WARNING (orig) = true; + suppress_warning (orig, OPT_Wreturn_type); return false; } @@ -5159,7 +5159,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) promise_type, fn_start); finish_expr_stmt (del_coro_fr); tree rethrow = build_throw (fn_start, NULL_TREE); - TREE_NO_WARNING (rethrow) = true; + suppress_warning (rethrow); finish_expr_stmt (rethrow); finish_handler (handler); TRY_HANDLERS (ramp_cleanup) = pop_stmt_list (TRY_HANDLERS (ramp_cleanup)); diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 33e1055..00b7772 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -101,8 +101,8 @@ genericize_eh_spec_block (tree *stmt_p) tree failure = build_call_n (call_unexpected_fn, 1, build_exc_ptr ()); *stmt_p = build_gimple_eh_filter_tree (body, allowed, failure); - TREE_NO_WARNING (*stmt_p) = true; - TREE_NO_WARNING (TREE_OPERAND (*stmt_p, 1)) = true; + suppress_warning (*stmt_p); + suppress_warning (TREE_OPERAND (*stmt_p, 1)); } /* Return the first non-compound statement in STMT. */ @@ -220,7 +220,7 @@ gimplify_expr_stmt (tree *stmt_p) { if (!IS_EMPTY_STMT (stmt) && !VOID_TYPE_P (TREE_TYPE (stmt)) - && !TREE_NO_WARNING (stmt)) + && !warning_suppressed_p (stmt, OPT_Wunused_value)) warning (OPT_Wunused_value, "statement with no effect"); } else @@ -1328,7 +1328,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) case THROW_EXPR: { location_t loc = location_of (stmt); - if (TREE_NO_WARNING (stmt)) + if (warning_suppressed_p (stmt /* What warning? */)) /* Never mind. */; else if (wtd->try_block) { @@ -2443,8 +2443,9 @@ cp_fold (tree x) ; else if (COMPARISON_CLASS_P (x)) { - if (TREE_NO_WARNING (org_x) && warn_nonnull_compare) - TREE_NO_WARNING (x) = 1; + if (warn_nonnull_compare + && warning_suppressed_p (org_x, OPT_Wnonnull_compare)) + suppress_warning (x, OPT_Wnonnull_compare); } /* Otherwise give up on optimizing these, let GIMPLE folders optimize those later on. */ @@ -2452,8 +2453,9 @@ cp_fold (tree x) || op1 != TREE_OPERAND (org_x, 1)) { x = build2_loc (loc, code, TREE_TYPE (org_x), op0, op1); - if (TREE_NO_WARNING (org_x) && warn_nonnull_compare) - TREE_NO_WARNING (x) = 1; + if (warn_nonnull_compare + && warning_suppressed_p (org_x, OPT_Wnonnull_compare)) + suppress_warning (x, OPT_Wnonnull_compare); } else x = org_x; @@ -2713,7 +2715,7 @@ cp_fold (tree x) if (EXPR_P (x) && TREE_CODE (x) == code) { TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (org_x); - TREE_NO_WARNING (x) = TREE_NO_WARNING (org_x); + copy_warning (x, org_x); } if (!c.evaluation_restricted_p ()) diff --git a/gcc/cp/cp-ubsan.c b/gcc/cp/cp-ubsan.c index 3dabb6a..7854594 100644 --- a/gcc/cp/cp-ubsan.c +++ b/gcc/cp/cp-ubsan.c @@ -81,7 +81,7 @@ cp_ubsan_instrument_vptr (location_t loc, tree op, tree type, bool is_addr, build_zero_cst (TREE_TYPE (op))); /* This is a compiler generated comparison, don't emit e.g. -Wnonnull-compare warning for it. */ - TREE_NO_WARNING (cond) = 1; + suppress_warning (cond, OPT_Wnonnull_compare); vptr = build3_loc (loc, COND_EXPR, uint64_type_node, cond, vptr, build_int_cst (uint64_type_node, 0)); } diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 330d658..d035e61 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -605,8 +605,6 @@ ignore_overflows (tree expr, tree orig) tree cp_fold_convert (tree type, tree expr) { - bool nowarn = TREE_NO_WARNING (expr); - tree conv; if (TREE_TYPE (expr) == type) conv = expr; @@ -630,8 +628,8 @@ cp_fold_convert (tree type, tree expr) conv = ignore_overflows (conv, expr); } - if (nowarn && TREE_CODE (expr) == TREE_CODE (conv)) - TREE_NO_WARNING (conv) = nowarn; + if (TREE_CODE (expr) == TREE_CODE (conv)) + copy_warning (conv, expr); return conv; } @@ -1208,7 +1206,7 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) /* The second part of a compound expr contains the value. */ tree op1 = TREE_OPERAND (expr,1); tree new_op1; - if (implicit != ICV_CAST && !TREE_NO_WARNING (expr)) + if (implicit != ICV_CAST && !warning_suppressed_p (expr /* What warning? */)) new_op1 = convert_to_void (op1, ICV_RIGHT_OF_COMMA, complain); else new_op1 = convert_to_void (op1, ICV_CAST, complain); @@ -1394,7 +1392,7 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) if (warn_unused_value && implicit != ICV_CAST && (complain & tf_warning) - && !TREE_NO_WARNING (expr) + && !warning_suppressed_p (expr, OPT_Wunused_value) && !is_reference) warning_at (loc, OPT_Wunused_value, "value computed is not used"); expr = TREE_OPERAND (expr, 0); @@ -1578,7 +1576,7 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) { if (implicit != ICV_CAST && warn_unused_value - && !TREE_NO_WARNING (expr) + && !warning_suppressed_p (expr, OPT_Wunused_value) && !processing_template_decl && !cp_unevaluated_operand && (complain & tf_warning)) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 66bcc4b..fa6af6f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -850,7 +850,7 @@ wrapup_namespace_globals () && !TREE_PUBLIC (decl) && !DECL_ARTIFICIAL (decl) && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl) - && !TREE_NO_WARNING (decl)) + && !warning_suppressed_p (decl, OPT_Wunused_function)) warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wunused_function, "%qF declared % but never defined", decl); @@ -13906,10 +13906,7 @@ grokdeclarator (const cp_declarator *declarator, decl = build_decl (id_loc, FIELD_DECL, unqualified_id, type); DECL_NONADDRESSABLE_P (decl) = bitfield; if (bitfield && !unqualified_id) - { - TREE_NO_WARNING (decl) = 1; - DECL_PADDING_P (decl) = 1; - } + DECL_PADDING_P (decl) = 1; if (storage_class == sc_mutable) { @@ -17495,7 +17492,7 @@ finish_function (bool inline_p) /* Don't complain if we are declared noreturn. */ && !TREE_THIS_VOLATILE (fndecl) && !DECL_NAME (DECL_RESULT (fndecl)) - && !TREE_NO_WARNING (fndecl) + && !warning_suppressed_p (fndecl, OPT_Wreturn_type) /* Structor return values (if any) are set by the compiler. */ && !DECL_CONSTRUCTOR_P (fndecl) && !DECL_DESTRUCTOR_P (fndecl) @@ -17523,7 +17520,7 @@ finish_function (bool inline_p) else if (warning_at (&richloc, OPT_Wreturn_type, "no return statement in function returning " "non-void")) - TREE_NO_WARNING (fndecl) = 1; + suppress_warning (fndecl, OPT_Wreturn_type); } /* Lambda closure members are implicitly constexpr if possible. */ @@ -17597,7 +17594,7 @@ finish_function (bool inline_p) && !DECL_READ_P (decl) && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl) - && !TREE_NO_WARNING (decl) + && !warning_suppressed_p (decl,OPT_Wunused_but_set_parameter) && !DECL_IN_SYSTEM_HEADER (decl) && TREE_TYPE (decl) != error_mark_node && !TYPE_REF_P (TREE_TYPE (decl)) @@ -18088,7 +18085,7 @@ require_deduced_type (tree decl, tsubst_flags_t complain) { if (undeduced_auto_decl (decl)) { - if (TREE_NO_WARNING (decl) && seen_error ()) + if (warning_suppressed_p (decl) && seen_error ()) /* We probably already complained about deduction failure. */; else if (complain & tf_error) error ("use of %qD before deduction of %", decl); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index e46fded..090a83b 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -4529,7 +4529,7 @@ no_linkage_error (tree decl) || (errorcount + sorrycount > 0 && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) - && TREE_NO_WARNING (decl)))) + && warning_suppressed_p (decl /* What warning? */)))) /* In C++11 it's ok if the decl is defined. */ return; @@ -5204,7 +5204,7 @@ c_parse_final_cleanups (void) && warning_at (DECL_SOURCE_LOCATION (decl), 0, "inline function %qD used but never defined", decl)) /* Avoid a duplicate warning from check_global_declaration. */ - TREE_NO_WARNING (decl) = 1; + suppress_warning (decl, OPT_Wunused); } /* So must decls that use a type with no linkage. */ diff --git a/gcc/cp/except.c b/gcc/cp/except.c index cbafc09..a8cea53 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -466,7 +466,8 @@ expand_end_catch_block (void) || DECL_DESTRUCTOR_P (current_function_decl))) { tree rethrow = build_throw (input_location, NULL_TREE); - TREE_NO_WARNING (rethrow) = true; + /* Disable all warnings for the generated rethrow statement. */ + suppress_warning (rethrow); finish_expr_stmt (rethrow); } } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 4bd942f..88f6f90 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3536,11 +3536,11 @@ build_new_1 (vec **placement, tree type, tree nelts, the arguments to the constructor call. */ { /* CLEANUP is compiler-generated, so no diagnostics. */ - TREE_NO_WARNING (cleanup) = true; + suppress_warning (cleanup); init_expr = build2 (TRY_CATCH_EXPR, void_type_node, init_expr, cleanup); /* Likewise, this try-catch is compiler-generated. */ - TREE_NO_WARNING (init_expr) = true; + suppress_warning (init_expr); } else /* Ack! First we allocate the memory. Then we set our sentry @@ -3562,7 +3562,7 @@ build_new_1 (vec **placement, tree type, tree nelts, sentry = TARGET_EXPR_SLOT (begin); /* CLEANUP is compiler-generated, so no diagnostics. */ - TREE_NO_WARNING (cleanup) = true; + suppress_warning (cleanup); TARGET_EXPR_CLEANUP (begin) = build3 (COND_EXPR, void_type_node, sentry, @@ -3576,7 +3576,7 @@ build_new_1 (vec **placement, tree type, tree nelts, build2 (COMPOUND_EXPR, void_type_node, init_expr, end)); /* Likewise, this is compiler-generated. */ - TREE_NO_WARNING (init_expr) = true; + suppress_warning (init_expr); } } } @@ -3823,7 +3823,7 @@ build_new (location_t loc, vec **placement, tree type, /* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain. */ rval = build1_loc (loc, NOP_EXPR, TREE_TYPE (rval), rval); - TREE_NO_WARNING (rval) = 1; + suppress_warning (rval, OPT_Wunused_value); return rval; } @@ -3995,7 +3995,7 @@ build_vec_delete_1 (location_t loc, tree base, tree maxindex, tree type, fold_convert (TREE_TYPE (base), nullptr_node)); /* This is a compiler generated comparison, don't emit e.g. -Wnonnull-compare warning for it. */ - TREE_NO_WARNING (cond) = 1; + suppress_warning (cond, OPT_Wnonnull_compare); body = build3_loc (loc, COND_EXPR, void_type_node, cond, body, integer_zero_node); COND_EXPR_IS_VEC_DELETE (body) = true; @@ -4665,7 +4665,7 @@ build_vec_init (tree base, tree maxindex, tree init, atype = build_pointer_type (atype); stmt_expr = build1 (NOP_EXPR, atype, stmt_expr); stmt_expr = cp_build_fold_indirect_ref (stmt_expr); - TREE_NO_WARNING (stmt_expr) = 1; + suppress_warning (stmt_expr /* What warning? */); } return stmt_expr; @@ -4935,7 +4935,7 @@ build_delete (location_t loc, tree otype, tree addr, /* This is a compiler generated comparison, don't emit e.g. -Wnonnull-compare warning for it. */ else if (TREE_CODE (ifexp) == NE_EXPR) - TREE_NO_WARNING (ifexp) = 1; + suppress_warning (ifexp, OPT_Wnonnull_compare); if (!integer_nonzerop (ifexp)) expr = build3 (COND_EXPR, void_type_node, ifexp, expr, void_node); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index dd74523..f268aab 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -3284,7 +3284,7 @@ defaultable_fn_check (tree fn) /* Avoid do_warn_unused_parameter warnings. */ for (tree p = FUNCTION_FIRST_USER_PARM (fn); p; p = DECL_CHAIN (p)) if (DECL_NAME (p)) - TREE_NO_WARNING (p) = 1; + suppress_warning (p, OPT_Wunused_parameter); if (current_class_type && TYPE_BEING_DEFINED (current_class_type)) /* Defer checking. */; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b7a4298..096580e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1,3 +1,4 @@ + /* -*- C++ -*- Parser. Copyright (C) 2000-2021 Free Software Foundation, Inc. Written by Mark Mitchell . @@ -5322,7 +5323,7 @@ cp_parser_fold_expression (cp_parser *parser, tree expr1) /* The operands of a fold-expression are cast-expressions, so binary or conditional expressions are not allowed. We check this here to avoid tentative parsing. */ - if (EXPR_P (expr1) && TREE_NO_WARNING (expr1)) + if (EXPR_P (expr1) && warning_suppressed_p (expr1, OPT_Wparentheses)) /* OK, the expression was parenthesized. */; else if (is_binary_op (TREE_CODE (expr1))) error_at (location_of (expr1), @@ -5604,7 +5605,10 @@ cp_parser_primary_expression (cp_parser *parser, /* Consume the `)'. */ token = cp_lexer_peek_token (parser->lexer); location_t close_paren_loc = token->location; + bool no_wparens = warning_suppressed_p (expr, OPT_Wparentheses); expr.set_range (open_paren_loc, close_paren_loc); + if (no_wparens) + suppress_warning (expr, OPT_Wparentheses); if (!parens.require_close (parser) && !cp_parser_uncommitted_to_tentative_parse_p (parser)) cp_parser_skip_to_end_of_statement (parser); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f73c747..e5a2a2c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10954,9 +10954,9 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc) constant expressions. */ if (!targs && limit_bad_template_recursion (tldcl)) { - /* Avoid no_linkage_errors and unused function warnings for this - decl. */ - TREE_NO_WARNING (tldcl) = 1; + /* Avoid no_linkage_errors and unused function (and all other) + warnings for this decl. */ + suppress_warning (tldcl); return false; } @@ -17079,7 +17079,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) tree op1 = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl); tree op2 = tsubst_copy (TREE_OPERAND (t, 2), args, complain, in_decl); r = build_nt (code, op0, op1, op2); - TREE_NO_WARNING (r) = TREE_NO_WARNING (t); + copy_warning (r, t); return r; } @@ -19172,8 +19172,7 @@ tsubst_omp_udr (tree t, tree args, tsubst_flags_t complain, tree in_decl) block = finish_omp_structured_block (block); block = maybe_cleanup_point_expr_void (block); add_decl_expr (omp_out); - if (TREE_NO_WARNING (DECL_EXPR_DECL (stmts[0]))) - TREE_NO_WARNING (omp_out) = 1; + copy_warning (omp_out, DECL_EXPR_DECL (stmts[0])); add_decl_expr (omp_in); finish_expr_stmt (block); } @@ -19854,17 +19853,17 @@ tsubst_copy_and_build (tree t, tree r = build_x_binary_op (input_location, TREE_CODE (t), op0, - (TREE_NO_WARNING (TREE_OPERAND (t, 0)) + (warning_suppressed_p (TREE_OPERAND (t, 0)) ? ERROR_MARK : TREE_CODE (TREE_OPERAND (t, 0))), op1, - (TREE_NO_WARNING (TREE_OPERAND (t, 1)) + (warning_suppressed_p (TREE_OPERAND (t, 1)) ? ERROR_MARK : TREE_CODE (TREE_OPERAND (t, 1))), /*overload=*/NULL, complain|decltype_flag); - if (EXPR_P (r) && TREE_NO_WARNING (t)) - TREE_NO_WARNING (r) = TREE_NO_WARNING (t); + if (EXPR_P (r)) + copy_warning (r, t); RETURN (r); } @@ -20000,8 +19999,8 @@ tsubst_copy_and_build (tree t, set and must be copied. In the latter case, build_x_modify_expr sets it and it must not be reset here. */ - if (TREE_NO_WARNING (t)) - TREE_NO_WARNING (r) = TREE_NO_WARNING (t); + if (warning_suppressed_p (t, OPT_Wparentheses)) + suppress_warning (r, OPT_Wparentheses); RETURN (r); } diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 82eaa28..fcb3308 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -536,14 +536,14 @@ build_if_nonnull (tree test, tree result, tsubst_flags_t complain) /* This is a compiler generated comparison, don't emit e.g. -Wnonnull-compare warning for it. */ - TREE_NO_WARNING (cond) = 1; + suppress_warning (cond, OPT_Wnonnull); null_ptr = cp_convert (TREE_TYPE (result), nullptr_node, complain); cond = build3 (COND_EXPR, TREE_TYPE (result), cond, result, null_ptr); /* Likewise, don't emit -Wnonnull for using the result to call a member function. */ - TREE_NO_WARNING (cond) = 1; + suppress_warning (cond, OPT_Wnonnull); return cond; } 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); } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 297da2b..2a14fa9 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1127,7 +1127,7 @@ build_cplus_array_type (tree elt_type, tree index_type, int dependent) /* Avoid spurious warnings with VLAs (c++/54583). */ if (TYPE_SIZE (t) && EXPR_P (TYPE_SIZE (t))) - TREE_NO_WARNING (TYPE_SIZE (t)) = 1; + suppress_warning (TYPE_SIZE (t), OPT_Wunused); /* Push these needs up to the ARRAY_TYPE so that initialization takes place more easily. */ diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 937581a..a483e1f 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3326,10 +3326,7 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name) member = DECL_CHAIN (member)) if (DECL_NAME (member) == member_name) break; - tree res = build_simple_component_ref (ptrmem, member); - - TREE_NO_WARNING (res) = 1; - return res; + return build_simple_component_ref (ptrmem, member); } /* Given an expression PTR for a pointer, return an expression @@ -3443,7 +3440,7 @@ cp_build_indirect_ref_1 (location_t loc, tree ptr, ref_operator errorstring, if (warn_strict_aliasing > 2 && cp_strict_aliasing_warning (EXPR_LOCATION (ptr), type, TREE_OPERAND (ptr, 0))) - TREE_NO_WARNING (ptr) = 1; + suppress_warning (ptr, OPT_Wstrict_aliasing); } if (VOID_TYPE_P (t)) @@ -4068,7 +4065,7 @@ cp_build_function_call_vec (tree function, vec **params, { tree c = extract_call_expr (ret); if (TREE_CODE (c) == CALL_EXPR) - TREE_NO_WARNING (c) = 1; + suppress_warning (c, OPT_Wnonnull); } if (allocated != NULL) @@ -4450,14 +4447,14 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain) if (!warn_address || (complain & tf_warning) == 0 || c_inhibit_evaluation_warnings != 0 - || TREE_NO_WARNING (op)) + || warning_suppressed_p (op, OPT_Waddress)) return; tree cop = fold_for_warn (op); if (TREE_CODE (cop) == ADDR_EXPR && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0)) - && !TREE_NO_WARNING (cop)) + && !warning_suppressed_p (cop, OPT_Waddress)) warning_at (location, OPT_Waddress, "the address of %qD will never " "be NULL", TREE_OPERAND (cop, 0)); @@ -4878,7 +4875,7 @@ cp_build_binary_op (const op_location_t &location, else if (TREE_CODE (type0) == ARRAY_TYPE && !char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type0))) /* Set by finish_parenthesized_expr. */ - && !TREE_NO_WARNING (op1) + && !warning_suppressed_p (op1, OPT_Wsizeof_array_div) && (complain & tf_warning)) maybe_warn_sizeof_array_div (location, first_arg, type0, op1, non_reference (type1)); @@ -5297,7 +5294,7 @@ cp_build_binary_op (const op_location_t &location, pfn0 = cp_fully_fold (pfn0); /* Avoid -Waddress warnings (c++/64877). */ if (TREE_CODE (pfn0) == ADDR_EXPR) - TREE_NO_WARNING (pfn0) = 1; + suppress_warning (pfn0, OPT_Waddress); pfn1 = pfn_from_ptrmemfunc (op1); pfn1 = cp_fully_fold (pfn1); delta0 = delta_from_ptrmemfunc (op0); @@ -7062,7 +7059,7 @@ unary_complex_lvalue (enum tree_code code, tree arg) tf_warning_or_error); arg = build2 (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result); - TREE_NO_WARNING (arg) = 1; + suppress_warning (arg /* What warning? */); return arg; } @@ -8978,7 +8975,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, TREE_SIDE_EFFECTS (result) = 1; if (!plain_assign) - TREE_NO_WARNING (result) = 1; + suppress_warning (result, OPT_Wparentheses); ret: if (preeval) @@ -9022,7 +9019,7 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, { if (rval == error_mark_node) return rval; - TREE_NO_WARNING (rval) = 1; + suppress_warning (rval /* What warning? */); if (processing_template_decl) { if (overload != NULL_TREE) @@ -9629,13 +9626,13 @@ convert_for_assignment (tree type, tree rhs, if (warn_parentheses && TREE_CODE (type) == BOOLEAN_TYPE && TREE_CODE (rhs) == MODIFY_EXPR - && !TREE_NO_WARNING (rhs) + && !warning_suppressed_p (rhs, OPT_Wparentheses) && TREE_CODE (TREE_TYPE (rhs)) != BOOLEAN_TYPE && (complain & tf_warning) && warning_at (rhs_loc, OPT_Wparentheses, "suggest parentheses around assignment used as " "truth value")) - TREE_NO_WARNING (rhs) = 1; + suppress_warning (rhs, OPT_Wparentheses); if (complain & tf_warning) warn_for_address_or_pointer_of_packed_member (type, rhs); -- cgit v1.1 From f9c80eb12c58126a94ad869380af5b88b752c06f Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 8 Jun 2021 17:44:13 -0400 Subject: c++: Failure to delay noexcept parsing with ptr-operator [PR100752] We weren't passing 'flags' to the recursive call to cp_parser_declarator in the ptr-operator case and as an effect, delayed parsing of noexcept didn't work as advertised. The following change passes more than just CP_PARSER_FLAGS_DELAY_NOEXCEPT but that doesn't seem to break anything. I'm now also passing member_p and static_p, as a consequence, two tests needed small tweaks. PR c++/100752 gcc/cp/ChangeLog: * parser.c (cp_parser_declarator): Pass flags down to cp_parser_declarator. Also pass static_p/member_p. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/noexcept69.C: New test. * g++.dg/parse/saved1.C: Adjust dg-error. * g++.dg/template/crash50.C: Likewise. --- gcc/cp/parser.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 096580e..02daa7a 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -22170,12 +22170,10 @@ cp_parser_declarator (cp_parser* parser, cp_parser_parse_tentatively (parser); /* Parse the dependent declarator. */ - declarator = cp_parser_declarator (parser, dcl_kind, - CP_PARSER_FLAGS_NONE, + declarator = cp_parser_declarator (parser, dcl_kind, flags, /*ctor_dtor_or_conv_p=*/NULL, /*parenthesized_p=*/NULL, - /*member_p=*/false, - friend_p, /*static_p=*/false); + member_p, friend_p, static_p); /* If we are parsing an abstract-declarator, we must handle the case where the dependent declarator is absent. */ -- cgit v1.1 From 90708f87b8d13da61f7d5cba7c6597fee0025bb1 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 26 Jun 2021 00:16:39 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 770d327..c53fb0c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,65 @@ +2021-06-26 Marek Polacek + + PR c++/100752 + * parser.c (cp_parser_declarator): Pass flags down to + cp_parser_declarator. Also pass static_p/member_p. + +2021-06-25 Martin Sebor + + * 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. + 2021-06-24 Patrick Palka PR c++/98832 -- cgit v1.1 From 2168bfb81448ae1bfa4351760a23d4ec051c2a00 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 24 Jun 2021 17:32:02 -0400 Subject: c++: constexpr aggr init of empty class [PR101040] This is basically the aggregate initializer version of PR97566; as in that bug, we are trying to initialize empty field 'obj' in 'single' when there's no CONSTRUCTOR entry for the 'single' base class subobject of 'derived'. As with that bug, the fix is to stop trying to add entries for empty fields, this time in cxx_eval_bare_aggregate. The change to the other function isn't necessary for this version of the patch, but seems worthwhile for robustness anyway. PR c++/101040 PR c++/97566 gcc/cp/ChangeLog: * class.c (is_empty_field): Handle null argument. * constexpr.c (cxx_eval_bare_aggregate): Discard initializer for empty field. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/no_unique_address13.C: New test. --- gcc/cp/class.c | 2 +- gcc/cp/constexpr.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index c89ffad..33093e1 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4220,7 +4220,7 @@ field_poverlapping_p (tree decl) bool is_empty_field (tree decl) { - if (TREE_CODE (decl) != FIELD_DECL) + if (!decl || TREE_CODE (decl) != FIELD_DECL) return false; bool r = (is_empty_class (TREE_TYPE (decl)) diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index a26aead..4cd9db3 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -4449,7 +4449,12 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, FOR_EACH_CONSTRUCTOR_ELT (v, i, index, value) { tree orig_value = value; - init_subob_ctx (ctx, new_ctx, index, value); + /* Like in cxx_eval_store_expression, omit entries for empty fields. */ + bool no_slot = TREE_CODE (type) == RECORD_TYPE && is_empty_field (index); + if (no_slot) + new_ctx = *ctx; + else + init_subob_ctx (ctx, new_ctx, index, value); int pos_hint = -1; if (new_ctx.ctor != ctx->ctor) { @@ -4495,6 +4500,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index)))); changed = true; } + else if (no_slot) + changed = true; else { if (TREE_CODE (type) == UNION_TYPE -- cgit v1.1 From 9f26e34a5a9614a5b66f146752ecef9ea67b3e2d Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Sat, 26 Jun 2021 11:05:54 -0400 Subject: c++: access scope during partial spec matching [PR96204] Here, when determining whether the partial specialization matches has_type_member, we do so from the scope of where the template-id appears rather than from the scope of the specialization, and this causes us to select the partial specialization (since Child::type is accessible from Parent). When we later instantiate this partial specialization, we've entered the scope of the specialization and so substitution into e.g. the DECL_CONTEXT of has_type_member::value fails with access errors since the friend declaration that we relied on to choose the partial specialization no longer applies. It seems the appropriate access scope from which to perform partial specialization matching is the specialization itself (similar to how we check access of base-clauses), which is what this patch implements. PR c++/96204 gcc/cp/ChangeLog: * pt.c (instantiate_class_template_1): Enter the scope of the type when calling most_specialized_partial_spec. gcc/testsuite/ChangeLog: * g++.dg/template/access40.C: New test. * g++.dg/template/access40a.C: New test. --- gcc/cp/pt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index e5a2a2c..f2039e0 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11769,8 +11769,11 @@ instantiate_class_template_1 (tree type) deferring_access_check_sentinel acs (dk_no_deferred); /* Determine what specialization of the original template to - instantiate. */ + instantiate; do this relative to the scope of the class for + sake of access checking. */ + push_nested_class (type); t = most_specialized_partial_spec (type, tf_warning_or_error); + pop_nested_class (); if (t == error_mark_node) return error_mark_node; else if (t) -- cgit v1.1 From 461f937b47278eaa4ca3c5507c80cca26af4b015 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 27 Jun 2021 00:16:24 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c53fb0c..3791ac4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2021-06-26 Patrick Palka + + PR c++/96204 + * pt.c (instantiate_class_template_1): Enter the scope of the + type when calling most_specialized_partial_spec. + +2021-06-26 Jason Merrill + + PR c++/101040 + PR c++/97566 + * class.c (is_empty_field): Handle null argument. + * constexpr.c (cxx_eval_bare_aggregate): Discard initializer + for empty field. + 2021-06-26 Marek Polacek PR c++/100752 -- cgit v1.1 From 362347c5a4e56d48c9af7ed7d9cc3feff0c2d219 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 29 Jun 2021 15:11:25 -0400 Subject: c++: don't treat member var as var template While looking at a partial instantiation issue I noticed that we were wrongly hitting the partial instantiation code when instantiating a static data member of a class template. I don't think this broke anything, but we don't need to do that (small) extra work. gcc/cp/ChangeLog: * pt.c (instantiate_decl): Only consider partial specializations of actual variable templates. --- gcc/cp/pt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f2039e0..d2936c1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -26003,7 +26003,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) td = template_for_substitution (d); args = gen_args; - if (VAR_P (d)) + if (variable_template_specialization_p (d)) { /* Look up an explicit specialization, if any. */ tree tid = lookup_template_variable (gen_tmpl, gen_args); -- cgit v1.1 From 6bc18203dd2a696cdfcd9d45eae3b9cce7b08822 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 30 Jun 2021 00:16:52 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3791ac4..01b29b1 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2021-06-29 Jason Merrill + + * pt.c (instantiate_decl): Only consider partial specializations of + actual variable templates. + 2021-06-26 Patrick Palka PR c++/96204 -- cgit v1.1 From e66d0b7b87d105d24da8c4784a0b907fb6b2c095 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 29 Jun 2021 14:30:51 -0400 Subject: c++: DR2397 - auto specifier for * and & to arrays [PR100975] This patch implements DR2397, which removes the restriction in [dcl.array]p4 that the array element type may not be a placeholder type. We don't need to worry about decltype(auto) here, so this allows code like int a[3]; auto (*p)[3] = &a; auto (&r)[3] = a; However, note that auto (&&r)[2] = { 1, 2 }; auto arr[2] = { 1, 2 }; still doesn't work (although one day it might) and neither does int arr[5]; auto x[5] = arr; given that auto deduction is performed in terms of function template argument deduction, so the array decays to *. PR c++/100975 DR 2397 gcc/cp/ChangeLog: * decl.c (create_array_type_for_decl): Allow array of auto. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/auto24.C: Remove dg-error. * g++.dg/cpp0x/auto3.C: Adjust dg-error. * g++.dg/cpp0x/auto42.C: Likewise. * g++.dg/cpp0x/initlist75.C: Likewise. * g++.dg/cpp0x/initlist80.C: Likewise. * g++.dg/diagnostic/auto1.C: Remove dg-error. * g++.dg/cpp23/auto-array.C: New test. --- gcc/cp/decl.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index fa6af6f..7672947 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10969,17 +10969,6 @@ create_array_type_for_decl (tree name, tree type, tree size, location_t loc) if (type == error_mark_node || size == error_mark_node) return error_mark_node; - /* 8.3.4/1: If the type of the identifier of D contains the auto - type-specifier, the program is ill-formed. */ - if (type_uses_auto (type)) - { - if (name) - error_at (loc, "%qD declared as array of %qT", name, type); - else - error ("creating array of %qT", type); - return error_mark_node; - } - /* If there are some types which cannot be array elements, issue an error-message and return. */ switch (TREE_CODE (type)) -- cgit v1.1 From c28e1d288ab727de6eb493e1aa2eadf5d5eef3ab Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 30 Jun 2021 13:12:36 -0400 Subject: c++: Fix push_access_scope and introduce RAII wrapper for it When push_access_scope is passed a TYPE_DECL for a class type (which can happen during e.g. satisfaction), we undesirably push only the enclosing context of the class instead of the class itself. This causes us to mishandle e.g. testcase below due to us not entering the scope of A before checking its constraints. This patch adjusts push_access_scope accordingly, and introduces an RAII wrapper for it. We make use of this wrapper right away by replacing the only user of push_nested_class_guard with this new wrapper, which means we can remove push_nested_class_guard (whose functionality is basically subsumed by the new wrapper). gcc/cp/ChangeLog: * constraint.cc (get_normalized_constraints_from_decl): Use push_access_scope_guard instead of push_nested_class_guard. * cp-tree.h (struct push_nested_class_guard): Replace with ... (struct push_access_scope_guard): ... this. * pt.c (push_access_scope): When the argument corresponds to a class type, push the class instead of its context. (pop_access_scope): Adjust accordingly. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-access2.C: New test. --- gcc/cp/constraint.cc | 7 +------ gcc/cp/cp-tree.h | 23 +++++++++++++---------- gcc/cp/pt.c | 7 ++++++- 3 files changed, 20 insertions(+), 17 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 6df3ca6..99d3ccc 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -926,12 +926,7 @@ get_normalized_constraints_from_decl (tree d, bool diag = false) tree norm = NULL_TREE; if (tree ci = get_constraints (decl)) { - push_nested_class_guard pncs (DECL_CONTEXT (d)); - - temp_override ovr (current_function_decl); - if (TREE_CODE (decl) == FUNCTION_DECL) - current_function_decl = decl; - + push_access_scope_guard pas (decl); norm = get_normalized_constraints_from_info (ci, tmpl, diag); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6f71371..58da746 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8463,21 +8463,24 @@ is_constrained_auto (const_tree t) return is_auto (t) && PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t); } -/* RAII class to push/pop class scope T; if T is not a class, do nothing. */ +/* RAII class to push/pop the access scope for T. */ -struct push_nested_class_guard +struct push_access_scope_guard { - bool push; - push_nested_class_guard (tree t) - : push (t && CLASS_TYPE_P (t)) + tree decl; + push_access_scope_guard (tree t) + : decl (t) { - if (push) - push_nested_class (t); + if (VAR_OR_FUNCTION_DECL_P (decl) + || TREE_CODE (decl) == TYPE_DECL) + push_access_scope (decl); + else + decl = NULL_TREE; } - ~push_nested_class_guard () + ~push_access_scope_guard () { - if (push) - pop_nested_class (); + if (decl) + pop_access_scope (decl); } }; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d2936c1..f8f7616 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -224,7 +224,7 @@ static void instantiate_body (tree pattern, tree args, tree d, bool nested); /* Make the current scope suitable for access checking when we are processing T. T can be FUNCTION_DECL for instantiated function template, VAR_DECL for static member variable, or TYPE_DECL for - alias template (needed by instantiate_decl). */ + for a class or alias template (needed by instantiate_decl). */ void push_access_scope (tree t) @@ -234,6 +234,9 @@ push_access_scope (tree t) if (DECL_FRIEND_CONTEXT (t)) push_nested_class (DECL_FRIEND_CONTEXT (t)); + else if (DECL_IMPLICIT_TYPEDEF_P (t) + && CLASS_TYPE_P (TREE_TYPE (t))) + push_nested_class (TREE_TYPE (t)); else if (DECL_CLASS_SCOPE_P (t)) push_nested_class (DECL_CONTEXT (t)); else if (deduction_guide_p (t) && DECL_ARTIFICIAL (t)) @@ -260,6 +263,8 @@ pop_access_scope (tree t) current_function_decl = saved_access_scope->pop(); if (DECL_FRIEND_CONTEXT (t) + || (DECL_IMPLICIT_TYPEDEF_P (t) + && CLASS_TYPE_P (TREE_TYPE (t))) || DECL_CLASS_SCOPE_P (t) || (deduction_guide_p (t) && DECL_ARTIFICIAL (t))) pop_nested_class (); -- cgit v1.1 From 25b6bfea5f14da53116f2d3efe2446de89b9bc03 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 1 Jul 2021 00:16:41 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 01b29b1..d861f29 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2021-06-30 Patrick Palka + + * constraint.cc (get_normalized_constraints_from_decl): Use + push_access_scope_guard instead of push_nested_class_guard. + * cp-tree.h (struct push_nested_class_guard): Replace with ... + (struct push_access_scope_guard): ... this. + * pt.c (push_access_scope): When the argument corresponds to + a class type, push the class instead of its context. + (pop_access_scope): Adjust accordingly. + +2021-06-30 Marek Polacek + + PR c++/100975 + DR 2397 + * decl.c (create_array_type_for_decl): Allow array of auto. + 2021-06-29 Jason Merrill * pt.c (instantiate_decl): Only consider partial specializations of -- cgit v1.1 From 613497aa6e28ca009d8498002424019d2a8a9ca5 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 30 Jun 2021 20:21:16 -0400 Subject: c++: Extend the PR96204 fix to variable templates too r12-1829 corrected the access scope during partial specialization matching of class templates, but overlooked the variable template case. This patch moves the access scope adjustment to within most_specialized_partial_spec so that all callers can benefit. This patch also adjusts a couple of these callers to avoid always passing the most general template of a variable template specialization, since that'd cause us to push the wrong access scope for e.g. the second testcase below (we'd push A instead of A/A). We ought to be passing the partially instantiated template instead. PR c++/96204 gcc/cp/ChangeLog: * pt.c (finish_template_variable): Pass the partially instantiated template and its args to instantiate_template. (instantiate_class_template_1): No need to call push_nested_class and pop_nested_class around the call to most_specialized_partial_spec. (instantiate_template_1): Pass the partially instantiated template to lookup_template_variable. (most_specialized_partial_spec): Use push_access_scope_guard to set the access scope appropriately. Use deferring_access_check_sentinel to force access to get checked immediately. (instantiate_decl): Just pass the VAR_DECL to most_specialized_partial_spec. gcc/testsuite/ChangeLog: * g++.dg/template/access41.C: New test. * g++.dg/template/access41a.C: New test. --- gcc/cp/pt.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f8f7616..dda6c9e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10268,10 +10268,6 @@ finish_template_variable (tree var, tsubst_flags_t complain) tree templ = TREE_OPERAND (var, 0); tree arglist = TREE_OPERAND (var, 1); - tree tmpl_args = DECL_TI_ARGS (DECL_TEMPLATE_RESULT (templ)); - arglist = add_outermost_template_args (tmpl_args, arglist); - - templ = most_general_template (templ); tree parms = DECL_TEMPLATE_PARMS (templ); arglist = coerce_innermost_template_parms (parms, arglist, templ, complain, /*req_all*/true, @@ -11774,11 +11770,8 @@ instantiate_class_template_1 (tree type) deferring_access_check_sentinel acs (dk_no_deferred); /* Determine what specialization of the original template to - instantiate; do this relative to the scope of the class for - sake of access checking. */ - push_nested_class (type); + instantiate. */ t = most_specialized_partial_spec (type, tf_warning_or_error); - pop_nested_class (); if (t == error_mark_node) return error_mark_node; else if (t) @@ -21134,7 +21127,7 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain) /* We need to determine if we're using a partial or explicit specialization now, because the type of the variable could be different. */ - tree tid = lookup_template_variable (gen_tmpl, targ_ptr); + tree tid = lookup_template_variable (tmpl, targ_ptr); tree elt = most_specialized_partial_spec (tid, complain); if (elt == error_mark_node) pattern = error_mark_node; @@ -24987,26 +24980,33 @@ most_specialized_partial_spec (tree target, tsubst_flags_t complain) tree outer_args = NULL_TREE; tree tmpl, args; + tree decl; if (TYPE_P (target)) { tree tinfo = CLASSTYPE_TEMPLATE_INFO (target); tmpl = TI_TEMPLATE (tinfo); args = TI_ARGS (tinfo); + decl = TYPE_NAME (target); } else if (TREE_CODE (target) == TEMPLATE_ID_EXPR) { tmpl = TREE_OPERAND (target, 0); args = TREE_OPERAND (target, 1); + decl = DECL_TEMPLATE_RESULT (tmpl); } else if (VAR_P (target)) { tree tinfo = DECL_TEMPLATE_INFO (target); tmpl = TI_TEMPLATE (tinfo); args = TI_ARGS (tinfo); + decl = target; } else gcc_unreachable (); + push_access_scope_guard pas (decl); + deferring_access_check_sentinel acs (dk_no_deferred); + tree main_tmpl = most_general_template (tmpl); /* For determining which partial specialization to use, only the @@ -26011,8 +26011,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) if (variable_template_specialization_p (d)) { /* Look up an explicit specialization, if any. */ - tree tid = lookup_template_variable (gen_tmpl, gen_args); - tree elt = most_specialized_partial_spec (tid, tf_warning_or_error); + tree elt = most_specialized_partial_spec (d, tf_warning_or_error); if (elt && elt != error_mark_node) { td = TREE_VALUE (elt); -- cgit v1.1 From a688c284dd3848b6c4ea553035f0f9769fb4fbc9 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 30 Jun 2021 20:44:52 -0400 Subject: c++: cxx_eval_array_reference and empty elem type [PR101194] Here the initializer for x is represented as an empty CONSTRUCTOR due to its empty element type. So during constexpr evaluation of the ARRAY_REF x[0], we end up trying to value initialize the omitted element at index 0, which fails because the element type is not default constructible. This patch makes cxx_eval_array_reference specifically handle the case where the element type is an empty type. PR c++/101194 gcc/cp/ChangeLog: * constexpr.c (cxx_eval_array_reference): When the element type is an empty type and the corresponding element is omitted, just return an empty CONSTRUCTOR instead of attempting value initialization. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-empty16.C: New test. --- gcc/cp/constexpr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 4cd9db3..39787f3 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3845,7 +3845,9 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, directly for non-aggregates to avoid creating a garbage CONSTRUCTOR. */ tree val; constexpr_ctx new_ctx; - if (CP_AGGREGATE_TYPE_P (elem_type)) + if (is_really_empty_class (elem_type, /*ignore_vptr*/false)) + return build_constructor (elem_type, NULL); + else if (CP_AGGREGATE_TYPE_P (elem_type)) { tree empty_ctor = build_constructor (init_list_type_node, NULL); val = digest_init (elem_type, empty_ctor, tf_warning_or_error); -- cgit v1.1 From bea7c16a467cd1278375df261e4bc1d2d6e48d3b Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 2 Jul 2021 00:16:47 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d861f29..13b009e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,28 @@ +2021-07-01 Patrick Palka + + PR c++/101194 + * constexpr.c (cxx_eval_array_reference): When the element type + is an empty type and the corresponding element is omitted, just + return an empty CONSTRUCTOR instead of attempting value + initialization. + +2021-07-01 Patrick Palka + + PR c++/96204 + * pt.c (finish_template_variable): Pass the partially + instantiated template and its args to instantiate_template. + (instantiate_class_template_1): No need to call + push_nested_class and pop_nested_class around the call to + most_specialized_partial_spec. + (instantiate_template_1): Pass the partially instantiated + template to lookup_template_variable. + (most_specialized_partial_spec): Use push_access_scope_guard + to set the access scope appropriately. Use + deferring_access_check_sentinel to force access to get checked + immediately. + (instantiate_decl): Just pass the VAR_DECL to + most_specialized_partial_spec. + 2021-06-30 Patrick Palka * constraint.cc (get_normalized_constraints_from_decl): Use -- cgit v1.1 From e3528ce197f8886869f95e8a8f901861a319851c Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 2 Jul 2021 13:54:57 -0400 Subject: c++: unqualified member template in constraint [PR101247] Here any_template_parm_r is failing to mark the template parameters implicitly used by the unqualified use of 'd' inside the constraint because the code to do so assumes each level of a template parameter list points to the corresponding primary template, but here the parameter level for A in the out-of-line definition of A::B does not (nor do the parameter levels for A and C in the definition of A::C), which causes us to overlook the sharing. So it seems we can't in general depend on the TREE_TYPE of a template parameter level being non-empty here. This patch partially fixes this by rewriting the relevant part of any_template_parm_r to not depend on the TREE_TYPE of outer levels. We still depend on the innermost level to point to the innermost primary template, so we still crash on the commented out line in the below testcase. PR c++/101247 gcc/cp/ChangeLog: * pt.c (any_template_parm_r) : Rewrite to use common_enclosing_class and to not depend on the TREE_TYPE of outer levels pointing to the corresponding primary template. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-memtmpl4.C: New test. --- gcc/cp/pt.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index dda6c9e..7e56ccf 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10731,24 +10731,11 @@ any_template_parm_r (tree t, void *data) { /* If T is a member template that shares template parameters with ctx_parms, we need to mark all those parameters for mapping. */ - tree dparms = DECL_TEMPLATE_PARMS (t); - tree cparms = ftpi->ctx_parms; - while (TMPL_PARMS_DEPTH (dparms) > ftpi->max_depth) - dparms = TREE_CHAIN (dparms); - while (TMPL_PARMS_DEPTH (cparms) > TMPL_PARMS_DEPTH (dparms)) - cparms = TREE_CHAIN (cparms); - while (dparms - && (TREE_TYPE (TREE_VALUE (dparms)) - != TREE_TYPE (TREE_VALUE (cparms)))) - dparms = TREE_CHAIN (dparms), - cparms = TREE_CHAIN (cparms); - if (dparms) - { - int ddepth = TMPL_PARMS_DEPTH (dparms); - tree dargs = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (t))); - for (int i = 0; i < ddepth; ++i) - WALK_SUBTREE (TMPL_ARGS_LEVEL (dargs, i+1)); - } + if (tree ctmpl = TREE_TYPE (INNERMOST_TEMPLATE_PARMS (ftpi->ctx_parms))) + if (tree com = common_enclosing_class (DECL_CONTEXT (t), + DECL_CONTEXT (ctmpl))) + if (tree ti = CLASSTYPE_TEMPLATE_INFO (com)) + WALK_SUBTREE (TI_ARGS (ti)); } break; -- cgit v1.1 From 2ca89394280da4afad6074ec3cb7136b6142af7b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 2 Jul 2021 21:57:24 +0200 Subject: openmp: Reject #pragma omp atomic update, [PR101297] I've noticed that we allow a trailing comma on OpenMP atomic construct if there is at least one clause. Commas should be only allowed to separate the clauses (or in OpenMP 5.1 to separate directive name from the clauses). 2021-07-02 Jakub Jelinek PR c/101297 * c-parser.c (c_parser_omp_atomic): Consume comma only if it appears before a CPP_NAME. * parser.c (cp_parser_omp_atomic): Consume comma only if it appears before a CPP_NAME. * c-c++-common/gomp/atomic-24.c: New test. --- gcc/cp/parser.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 02daa7a..3550cd0 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -39171,7 +39171,9 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) { - if (!first && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + if (!first + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) cp_lexer_consume_token (parser->lexer); first = false; -- cgit v1.1 From 9984f63aab93a370101966b7eb198dc61130b3c8 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 2 Jul 2021 21:59:21 +0200 Subject: openmp: Initial support for OpenMP directives expressed as C++11 attributes This is an OpenMP 5.1 feature, but I think it is something very useful for OpenMP users, so I'm committing it now instead of waiting until all 5.0 work is done. The support is incomplete, only attributes on statements (or block local declarations) are supported right now, while for non-executable directives they should be also supported at namespace scope and at class scope, and for declarations in all places that appertain to the declarations rather than e.g. types. I need to also fix up handling of C++11 non-OpenMP attributes mixed with OpenMP attributes before block local declarations (currently it throws them away), probably reject if the directives appertain to labels etc. In order not to complicate all the OpenMP directive parsing, it is done by remembering the tokens from the attribute, slightly adjusting them and feeding them through a temporary new lexer to cp_parse_pragma. 2021-07-02 Jakub Jelinek gcc/c-family/ * c-common.h (enum c_omp_directive_kind): New enum. (struct c_omp_directive): New type. (c_omp_categorize_directive): Declare. * c-omp.c (omp_directives): New variable. (c_omp_categorize_directive): New function. gcc/cp/ * parser.h (struct cp_lexer): Add in_omp_attribute_pragma member. (struct cp_omp_declare_simd_data): Likewise. * cp-tree.h (enum cp_tree_index): Add CPTI_OMP_IDENTIFIER. (omp_identifier): Define. * parser.c (cp_parser_skip_to_pragma_eol): Handle in_omp_attribute_pragma CPP_PRAGMA_EOL followed by CPP_EOF. (cp_parser_require_pragma_eol): Likewise. (struct cp_omp_attribute_data): New type. (cp_parser_handle_statement_omp_attributes): New function. (cp_parser_statement): Handle OpenMP directives in statement's attribute-specifier-seq. (cp_parser_omp_directive_args, cp_parser_omp_sequence_args): New functions. (cp_parser_std_attribute): Handle omp::directive and omp::sequence attributes. (cp_parser_omp_all_clauses): If in_omp_attribute_pragma, allow a comma also before the first clause. (cp_parser_omp_allocate): Likewise. (cp_parser_omp_atomic): Likewise. (cp_parser_omp_depobj): Likewise. (cp_parser_omp_flush): Likewise. (cp_parser_omp_ordered): Likewise. (cp_parser_omp_declare_simd): Save in_omp_attribute_pragma into struct cp_omp_declare_simd_data. (cp_finish_omp_declare_variant): Add in_omp_attribute_pragma argument. If set, allow a comma also before match clause. (cp_parser_late_parsing_omp_declare_simd): If in_omp_attribute_pragma, allow a comma also before the first clause. Adjust cp_finish_omp_declare_variant caller. (cp_parser_omp_declare_target): If in_omp_attribute_pragma, allow a comma also before the first clause. (cp_parser_omp_declare_reduction_exprs): Likewise. (cp_parser_omp_requires): Likewise. * decl.c (initialize_predefined_identifiers): Initialize omp_identifier. * decl2.c (cplus_decl_attributes): Reject omp::directive and omp::sequence attributes. gcc/testsuite/ * g++.dg/gomp/attrs-1.C: New test. * g++.dg/gomp/attrs-2.C: New test. * g++.dg/gomp/attrs-3.C: New test. --- gcc/cp/cp-tree.h | 2 + gcc/cp/decl.c | 1 + gcc/cp/decl2.c | 25 ++++ gcc/cp/parser.c | 399 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- gcc/cp/parser.h | 6 + 5 files changed, 423 insertions(+), 10 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 58da746..b450157 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -176,6 +176,7 @@ enum cp_tree_index CPTI_HEAP_DELETED_IDENTIFIER, CPTI_HEAP_VEC_UNINIT_IDENTIFIER, CPTI_HEAP_VEC_IDENTIFIER, + CPTI_OMP_IDENTIFIER, CPTI_LANG_NAME_C, CPTI_LANG_NAME_CPLUSPLUS, @@ -337,6 +338,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; #define heap_deleted_identifier cp_global_trees[CPTI_HEAP_DELETED_IDENTIFIER] #define heap_vec_uninit_identifier cp_global_trees[CPTI_HEAP_VEC_UNINIT_IDENTIFIER] #define heap_vec_identifier cp_global_trees[CPTI_HEAP_VEC_IDENTIFIER] +#define omp_identifier cp_global_trees[CPTI_OMP_IDENTIFIER] #define lang_name_c cp_global_trees[CPTI_LANG_NAME_C] #define lang_name_cplusplus cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS] diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 7672947..ebe1318 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4387,6 +4387,7 @@ initialize_predefined_identifiers (void) {"heap deleted", &heap_deleted_identifier, cik_normal}, {"heap [] uninit", &heap_vec_uninit_identifier, cik_normal}, {"heap []", &heap_vec_identifier, cik_normal}, + {"omp", &omp_identifier, cik_normal}, {NULL, NULL, cik_normal} }; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 090a83b..9564b0d 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1584,6 +1584,31 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) cp_check_const_attributes (attributes); + if ((flag_openmp || flag_openmp_simd) && attributes != error_mark_node) + { + bool diagnosed = false; + for (tree *pa = &attributes; *pa; ) + { + if (get_attribute_namespace (*pa) == omp_identifier) + { + tree name = get_attribute_name (*pa); + if (is_attribute_p ("directive", name) + || is_attribute_p ("sequence", name)) + { + if (!diagnosed) + { + error ("% not allowed to be specified in this " + "context", name); + diagnosed = true; + } + *pa = TREE_CHAIN (*pa); + continue; + } + } + pa = &TREE_CHAIN (*pa); + } + } + if (TREE_CODE (*decl) == TEMPLATE_DECL) decl = &DECL_TEMPLATE_RESULT (*decl); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 3550cd0..93698aa 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1,4 +1,3 @@ - /* -*- C++ -*- Parser. Copyright (C) 2000-2021 Free Software Foundation, Inc. Written by Mark Mitchell . @@ -4061,6 +4060,14 @@ cp_parser_skip_to_pragma_eol (cp_parser* parser, cp_token *pragma_tok) /* Ensure that the pragma is not parsed again. */ cp_lexer_purge_tokens_after (parser->lexer, pragma_tok); parser->lexer->in_pragma = false; + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_EOF)) + { + parser->lexer = parser->lexer->next; + /* Put the current source position back where it was before this + lexer was pushed. */ + cp_lexer_set_source_position_from_token (parser->lexer->next_token); + } } } @@ -4073,6 +4080,14 @@ cp_parser_require_pragma_eol (cp_parser *parser, cp_token *pragma_tok) parser->lexer->in_pragma = false; if (!cp_parser_require (parser, CPP_PRAGMA_EOL, RT_PRAGMA_EOL)) cp_parser_skip_to_pragma_eol (parser, pragma_tok); + else if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_EOF)) + { + parser->lexer = parser->lexer->next; + /* Put the current source position back where it was before this + lexer was pushed. */ + cp_lexer_set_source_position_from_token (parser->lexer->next_token); + } } /* This is a simple wrapper around make_typename_type. When the id is @@ -11631,6 +11646,187 @@ add_debug_begin_stmt (location_t loc) add_stmt (stmt); } +struct cp_omp_attribute_data +{ + cp_token_cache *tokens; + const c_omp_directive *dir; + c_omp_directive_kind kind; +}; + +/* Handle omp::directive and omp::sequence attributes in ATTRS + (if any) at the start of a statement. */ + +static tree +cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) +{ + if (!flag_openmp && !flag_openmp_simd) + return attrs; + + auto_vec vec; + int cnt = 0; + int tokens = 0; + for (tree *pa = &attrs; *pa; ) + if (get_attribute_namespace (*pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (*pa))) + { + cnt++; + for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + const char *directive[3] = {}; + for (int i = 0; i < 3; i++) + { + tree id = NULL_TREE; + if (first + i == last) + break; + if (first[i].type == CPP_NAME) + id = first[i].u.value; + else if (first[i].type == CPP_KEYWORD) + id = ridpointers[(int) first[i].keyword]; + else + break; + directive[i] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + { + error_at (first->location, + "unknown OpenMP directive name in %" + " attribute argument"); + continue; + } + c_omp_directive_kind kind = dir->kind; + if (dir->id == PRAGMA_OMP_ORDERED) + { + /* ordered is C_OMP_DIR_CONSTRUCT only if it doesn't contain + depend clause. */ + if (directive[1] && strcmp (directive[1], "depend") == 0) + kind = C_OMP_DIR_STANDALONE; + else if (first + 2 < last + && first[1].type == CPP_COMMA + && first[2].type == CPP_NAME + && strcmp (IDENTIFIER_POINTER (first[2].u.value), + "depend") == 0) + kind = C_OMP_DIR_STANDALONE; + } + /* else if (dir->id == PRAGMA_OMP_ERROR) + { + error with at(execution) clause is C_OMP_DIR_STANDALONE. + } */ + cp_omp_attribute_data v = { DEFPARSE_TOKENS (d), dir, kind }; + vec.safe_push (v); + if (flag_openmp || dir->simd) + tokens += (last - first) + 1; + } + cp_omp_attribute_data v = {}; + vec.safe_push (v); + *pa = TREE_CHAIN (*pa); + } + else + pa = &TREE_CHAIN (*pa); + + unsigned int i; + cp_omp_attribute_data *v; + cp_omp_attribute_data *construct_seen = nullptr; + cp_omp_attribute_data *standalone_seen = nullptr; + cp_omp_attribute_data *prev_standalone_seen = nullptr; + FOR_EACH_VEC_ELT (vec, i, v) + if (v->tokens) + { + if (v->kind == C_OMP_DIR_CONSTRUCT && !construct_seen) + construct_seen = v; + else if (v->kind == C_OMP_DIR_STANDALONE && !standalone_seen) + standalone_seen = v; + } + else + { + if (standalone_seen && !prev_standalone_seen) + { + prev_standalone_seen = standalone_seen; + standalone_seen = nullptr; + } + } + + if (cnt > 1 && construct_seen) + { + error_at (construct_seen->tokens->first->location, + "OpenMP construct among % attributes" + " requires all % attributes on the" + " same statement to be in the same %"); + return attrs; + } + if (cnt > 1 && standalone_seen && prev_standalone_seen) + { + error_at (standalone_seen->tokens->first->location, + "multiple OpenMP standalone directives among" + " % attributes must be all within the" + " same %"); + return attrs; + } + + if (prev_standalone_seen) + standalone_seen = prev_standalone_seen; + if (standalone_seen + && !cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + error_at (standalone_seen->tokens->first->location, + "standalone OpenMP directives in % attribute" + " can only appear on an empty statement"); + return attrs; + } + + if (!tokens) + return attrs; + tokens++; + cp_lexer *lexer = cp_lexer_alloc (); + lexer->debugging_p = parser->lexer->debugging_p; + vec_safe_reserve (lexer->buffer, tokens, true); + FOR_EACH_VEC_ELT (vec, i, v) + { + if (!v->tokens) + continue; + if (!flag_openmp && !v->dir->simd) + continue; + cp_token *first = v->tokens->first; + cp_token *last = v->tokens->last; + cp_token tok = {}; + tok.type = CPP_PRAGMA; + tok.keyword = RID_MAX; + tok.u.value = build_int_cst (NULL, v->dir->id); + tok.location = first->location; + lexer->buffer->quick_push (tok); + while (++first < last) + lexer->buffer->quick_push (*first); + tok = {}; + tok.type = CPP_PRAGMA_EOL; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + } + cp_token tok = {}; + tok.type = CPP_EOF; + tok.keyword = RID_MAX; + tok.location = lexer->buffer->last ().location; + lexer->buffer->quick_push (tok); + lexer->next = parser->lexer; + lexer->next_token = lexer->buffer->address (); + lexer->last_token = lexer->next_token + + lexer->buffer->length () + - 1; + lexer->in_omp_attribute_pragma = true; + parser->lexer = lexer; + /* Move the current source position to that of the first token in the + new lexer. */ + cp_lexer_set_source_position_from_token (lexer->next_token); + return attrs; +} + /* Parse a statement. statement: @@ -11681,8 +11877,10 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, tree statement, std_attrs = NULL_TREE; cp_token *token; location_t statement_location, attrs_loc; + bool in_omp_attribute_pragma; restart: + in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; if (if_p != NULL) *if_p = false; /* There is no statement yet. */ @@ -11704,6 +11902,9 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, std_attrs = NULL_TREE; } + if (std_attrs && (flag_openmp || flag_openmp_simd)) + std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs); + /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); /* Remember the location of the first token in the statement. */ @@ -11821,6 +12022,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, a statement all its own. */ else if (token->type == CPP_PRAGMA) { + cp_lexer *lexer = parser->lexer; + bool do_restart = false; /* Only certain OpenMP pragmas are attached to statements, and thus are considered statements themselves. All others are not. In the context of a compound, accept the pragma as a "statement" and @@ -11829,6 +12032,13 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, if (in_compound) cp_parser_pragma (parser, pragma_compound, if_p); else if (!cp_parser_pragma (parser, pragma_stmt, if_p)) + do_restart = true; + if (lexer->in_omp_attribute_pragma && !in_omp_attribute_pragma) + { + gcc_assert (parser->lexer != lexer); + cp_lexer_destroy (lexer); + } + if (do_restart) goto restart; return; } @@ -27935,6 +28145,92 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */) return nreverse (attribute_list); } +/* Parse arguments of omp::directive attribute. + + ( directive-name ,[opt] clause-list[opt] ) + + For directive just remember the first/last tokens for subsequent + parsing. */ + +static void +cp_parser_omp_directive_args (cp_parser *parser, tree attribute) +{ + cp_token *first = cp_lexer_peek_nth_token (parser->lexer, 2); + if (first->type == CPP_CLOSE_PAREN) + { + cp_lexer_consume_token (parser->lexer); + error_at (first->location, "expected OpenMP directive name"); + cp_lexer_consume_token (parser->lexer); + TREE_VALUE (attribute) = NULL_TREE; + return; + } + for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 2; n; --n) + cp_lexer_consume_token (parser->lexer); + cp_token *last = cp_lexer_peek_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + tree arg = make_node (DEFERRED_PARSE); + DEFPARSE_TOKENS (arg) = cp_token_cache_new (first, last); + DEFPARSE_INSTANTIATIONS (arg) = nullptr; + TREE_VALUE (attribute) = tree_cons (NULL_TREE, arg, TREE_VALUE (attribute)); +} + +/* Parse arguments of omp::sequence attribute. + + ( omp::[opt] directive-attr [ , omp::[opt] directive-attr ]... ) */ + +static void +cp_parser_omp_sequence_args (cp_parser *parser, tree attribute) +{ + matching_parens parens; + parens.consume_open (parser); + do + { + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_NAME + && token->u.value == omp_identifier + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_SCOPE)) + { + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + token = cp_lexer_peek_token (parser->lexer); + } + bool directive = false; + const char *p; + if (token->type != CPP_NAME) + p = ""; + else + p = IDENTIFIER_POINTER (token->u.value); + if (strcmp (p, "directive") == 0) + directive = true; + else if (strcmp (p, "sequence") != 0) + { + error_at (token->location, "expected % or %"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/true, + /*consume_paren=*/false); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + cp_lexer_consume_token (parser->lexer); + } + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)) + cp_parser_required_error (parser, RT_OPEN_PAREN, false, + UNKNOWN_LOCATION); + else if (directive) + cp_parser_omp_directive_args (parser, attribute); + else + cp_parser_omp_sequence_args (parser, attribute); + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + cp_lexer_consume_token (parser->lexer); + } + while (1); + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, true, false, + /*consume_paren=*/true); +} + /* Parse a standard C++11 attribute. The returned representation is a TREE_LIST which TREE_PURPOSE is @@ -28066,7 +28362,18 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) /* Now parse the optional argument clause of the attribute. */ if (token->type != CPP_OPEN_PAREN) - return attribute; + { + if ((flag_openmp || flag_openmp_simd) + && attr_ns == omp_identifier + && (is_attribute_p ("directive", attr_id) + || is_attribute_p ("sequence", attr_id))) + { + error_at (token->location, "% attribute requires argument", + attr_id); + return NULL_TREE; + } + return attribute; + } { vec *vec; @@ -28093,6 +28400,23 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) if (as == NULL) { + if ((flag_openmp || flag_openmp_simd) && attr_ns == omp_identifier) + { + if (is_attribute_p ("directive", attr_id)) + { + cp_parser_omp_directive_args (parser, attribute); + return attribute; + } + else if (is_attribute_p ("sequence", attr_id)) + { + TREE_VALUE (TREE_PURPOSE (attribute)) + = get_identifier ("directive"); + cp_parser_omp_sequence_args (parser, attribute); + TREE_VALUE (attribute) = nreverse (TREE_VALUE (attribute)); + return attribute; + } + } + /* For unknown attributes, just skip balanced tokens instead of trying to parse the arguments. */ for (size_t n = cp_parser_skip_balanced_tokens (parser, 1) - 1; n; --n) @@ -38675,7 +38999,12 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, if (nested && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) break; - if (!first) + if (!first + /* OpenMP 5.1 allows optional comma in between directive-name and + clauses everywhere, but as we aren't done with OpenMP 5.0 + implementation yet, let's allow it for now only in C++11 + attributes. */ + || (parser->lexer->in_omp_attribute_pragma && nested != 2)) { if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) cp_lexer_consume_token (parser->lexer); @@ -39080,6 +39409,12 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) location_t loc = pragma_tok->location; tree nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_ALLOCATE, NULL_TREE); + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { matching_parens parens; @@ -39171,7 +39506,8 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) { - if (!first + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if ((!first || parser->lexer->in_omp_attribute_pragma) && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) cp_lexer_consume_token (parser->lexer); @@ -39735,6 +40071,10 @@ cp_parser_omp_depobj (cp_parser *parser, cp_token *pragma_tok) tree clause = NULL_TREE; enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE; location_t c_loc = cp_lexer_peek_token (parser->lexer)->location; + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -39815,6 +40155,11 @@ static void cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok) { enum memmodel mo = MEMMODEL_LAST; + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -41175,10 +41520,16 @@ cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context, bool *if_p) { location_t loc = pragma_tok->location; + int n = 1; - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + n = 2; + + if (cp_lexer_nth_token_is (parser->lexer, n, CPP_NAME)) { - tree id = cp_lexer_peek_token (parser->lexer)->u.value; + tree id = cp_lexer_peek_nth_token (parser->lexer, n)->u.value; const char *p = IDENTIFIER_POINTER (id); if (strcmp (p, "depend") == 0) @@ -43020,6 +43371,7 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, data.error_seen = false; data.fndecl_seen = false; data.variant_p = variant_p; + data.in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; data.tokens = vNULL; data.clauses = NULL_TREE; /* It is safe to take the address of a local variable; it will only be @@ -43458,7 +43810,7 @@ cp_parser_omp_context_selector_specification (cp_parser *parser, static tree cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, - tree attrs) + tree attrs, bool in_omp_attribute_pragma) { matching_parens parens; if (!parens.require_open (parser)) @@ -43516,6 +43868,12 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, location_t finish_loc = get_finish (varid.get_location ()); location_t varid_loc = make_location (caret_loc, start_loc, finish_loc); + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + const char *clause = ""; location_t match_loc = cp_lexer_peek_token (parser->lexer)->location; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) @@ -43588,6 +43946,12 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) cp_lexer_consume_token (parser->lexer); if (strcmp (kind, "simd") == 0) { + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (data->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, "#pragma omp declare simd", pragma_tok); @@ -43602,7 +43966,9 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) else { gcc_assert (strcmp (kind, "variant") == 0); - attrs = cp_finish_omp_declare_variant (parser, pragma_tok, attrs); + attrs + = cp_finish_omp_declare_variant (parser, pragma_tok, attrs, + data->in_omp_attribute_pragma); } cp_parser_pop_lexer (parser); } @@ -43633,7 +43999,11 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) tree clauses = NULL_TREE; int device_type = 0; bool only_device_type = true; - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + || (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))) clauses = cp_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, "#pragma omp declare target", pragma_tok); @@ -43812,6 +44182,12 @@ cp_parser_omp_declare_reduction_exprs (tree fndecl, cp_parser *parser) if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) return false; + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + const char *p = ""; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { @@ -44246,7 +44622,10 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok) location_t loc = pragma_tok->location; while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) { - if (!first && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if ((!first || parser->lexer->in_omp_attribute_pragma) + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) cp_lexer_consume_token (parser->lexer); first = false; diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index a468b69..5ef7047 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -113,6 +113,10 @@ struct GTY (()) cp_lexer { /* True if we're in the context of parsing a pragma, and should not increment past the end-of-line marker. */ bool in_pragma; + + /* True if we're in the context of OpenMP directives written as C++11 + attributes turned into pragma. */ + bool in_omp_attribute_pragma; }; @@ -208,6 +212,8 @@ struct cp_omp_declare_simd_data { bool error_seen; /* Set if error has been reported. */ bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */ bool variant_p; /* Set for #pragma omp declare variant. */ + bool in_omp_attribute_pragma; /* True if declare simd/variant comes from + C++11 attribute rather than pragma. */ vec tokens; tree clauses; }; -- cgit v1.1 From 7a60a6e8b36dec960939494baef0f1f15dbfc450 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 3 Jul 2021 00:16:31 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 13b009e..90a2d2a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,56 @@ +2021-07-02 Jakub Jelinek + + * parser.h (struct cp_lexer): Add in_omp_attribute_pragma member. + (struct cp_omp_declare_simd_data): Likewise. + * cp-tree.h (enum cp_tree_index): Add CPTI_OMP_IDENTIFIER. + (omp_identifier): Define. + * parser.c (cp_parser_skip_to_pragma_eol): Handle + in_omp_attribute_pragma CPP_PRAGMA_EOL followed by CPP_EOF. + (cp_parser_require_pragma_eol): Likewise. + (struct cp_omp_attribute_data): New type. + (cp_parser_handle_statement_omp_attributes): New function. + (cp_parser_statement): Handle OpenMP directives in statement's + attribute-specifier-seq. + (cp_parser_omp_directive_args, cp_parser_omp_sequence_args): New + functions. + (cp_parser_std_attribute): Handle omp::directive and omp::sequence + attributes. + (cp_parser_omp_all_clauses): If in_omp_attribute_pragma, allow + a comma also before the first clause. + (cp_parser_omp_allocate): Likewise. + (cp_parser_omp_atomic): Likewise. + (cp_parser_omp_depobj): Likewise. + (cp_parser_omp_flush): Likewise. + (cp_parser_omp_ordered): Likewise. + (cp_parser_omp_declare_simd): Save in_omp_attribute_pragma + into struct cp_omp_declare_simd_data. + (cp_finish_omp_declare_variant): Add in_omp_attribute_pragma + argument. If set, allow a comma also before match clause. + (cp_parser_late_parsing_omp_declare_simd): If in_omp_attribute_pragma, + allow a comma also before the first clause. Adjust + cp_finish_omp_declare_variant caller. + (cp_parser_omp_declare_target): If in_omp_attribute_pragma, allow + a comma also before the first clause. + (cp_parser_omp_declare_reduction_exprs): Likewise. + (cp_parser_omp_requires): Likewise. + * decl.c (initialize_predefined_identifiers): Initialize + omp_identifier. + * decl2.c (cplus_decl_attributes): Reject omp::directive and + omp::sequence attributes. + +2021-07-02 Jakub Jelinek + + PR c/101297 + * parser.c (cp_parser_omp_atomic): Consume comma only if it + appears before a CPP_NAME. + +2021-07-02 Patrick Palka + + PR c++/101247 + * pt.c (any_template_parm_r) : Rewrite to + use common_enclosing_class and to not depend on the TREE_TYPE + of outer levels pointing to the corresponding primary template. + 2021-07-01 Patrick Palka PR c++/101194 -- cgit v1.1 From 4f6e181181a48c341e524653cae0885fd170131e Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Tue, 6 Jul 2021 14:13:31 -0600 Subject: Remove support for %G and %K. gcc/c-family/ChangeLog: * c-format.c (gcc_tdiag_char_table): Remove support for %G and %K. (gcc_cdiag_char_table): Same. (gcc_cxxdiag_char_table): Same. gcc/c/ChangeLog: * c-objc-common.c (c_tree_printer): Remove support for %G and %K. gcc/cp/ChangeLog: * error.c (cp_printer): Remove support for %G and %K. gcc/ChangeLog: * gimple-pretty-print.c (percent_G_format): Remove. * tree-diagnostic.c (default_tree_printer): Remove calls. * tree-pretty-print.c (percent_K_format): Remove. * tree-pretty-print.h (percent_K_format): Remove. gcc/testsuite/ChangeLog: * gcc.dg/format/gcc_diag-10.c: Update expected warnings. * gcc.dg/plugin/diagnostic_plugin_test_inlining.c: Remove %G. --- gcc/cp/error.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 4a89b34..012a4ec 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -4338,10 +4338,8 @@ defer_phase_2_of_type_diff (deferred_printed_type *deferred, %D declaration. %E expression. %F function declaration. - %G gcall * %H type difference (from). %I type difference (to). - %K tree %L language as used in extern "lang". %O binary operator. %P function parameter whose position is indicated by an integer. @@ -4391,9 +4389,6 @@ cp_printer (pretty_printer *pp, text_info *text, const char *spec, break; case 'E': result = expr_to_string (next_tree); break; case 'F': result = fndecl_to_string (next_tree, verbose); break; - case 'G': - percent_G_format (text); - return true; case 'H': defer_phase_2_of_type_diff (&postprocessor->m_type_a, next_tree, buffer_ptr, verbose, *quoted); @@ -4402,10 +4397,6 @@ cp_printer (pretty_printer *pp, text_info *text, const char *spec, defer_phase_2_of_type_diff (&postprocessor->m_type_b, next_tree, buffer_ptr, verbose, *quoted); return true; - case 'K': - t = va_arg (*text->args_ptr, tree); - percent_K_format (text, EXPR_LOCATION (t), TREE_BLOCK (t)); - return true; case 'L': result = language_to_string (next_lang); break; case 'O': result = op_to_string (false, next_tcode); break; case 'P': result = parm_to_string (next_int); break; -- cgit v1.1 From 6fba0eea8d6464966ac6d37af98a7487a9a03d19 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 7 Jul 2021 00:17:12 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 90a2d2a..31deb04 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,7 @@ +2021-07-06 Martin Sebor + + * error.c (cp_printer): Remove support for %G and %K. + 2021-07-02 Jakub Jelinek * parser.h (struct cp_lexer): Add in_omp_attribute_pragma member. -- cgit v1.1 From 9bf9f27ac6db4823628c435da9b242fd82bf8d68 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Thu, 8 Jul 2021 11:34:27 -0600 Subject: Use Object Size Type zero for -Warray-bounds [PR101374]. Resolves: PR bootstrap/101374 - -Warray-bounds accessing a member subobject as derived gcc/cp/ChangeLog: PR bootstrap/101374 * module.cc (module_state::read_macro_maps): Temporarily disable -Warray-bounds. (module_state::install_macros): Same. gcc/ChangeLog: PR bootstrap/101374 * gimple-array-bounds.cc (array_bounds_checker::check_mem_ref): Use Object Size Type 0 instead of 1. gcc/testsuite/ChangeLog: PR bootstrap/101374 * c-c++-common/Warray-bounds-3.c: Xfail assertion. * c-c++-common/Warray-bounds-4.c: Same. --- gcc/cp/module.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index f259515..8a890c1 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -16301,11 +16301,18 @@ module_state::read_macro_maps () } if (count) sec.set_overrun (); + + /* FIXME: Re-enable or fix after root causing. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" + dump (dumper::LOCATION) && dump ("Macro:%u %I %u/%u*2 locations [%u,%u)", ix, identifier (node), runs, n_tokens, MAP_START_LOCATION (macro), MAP_START_LOCATION (macro) + n_tokens); + +#pragma GCC diagnostic pop } location_t lwm = sec.u (); macro_locs.first = lwm - slurp->loc_deltas.second; @@ -16911,6 +16918,10 @@ module_state::install_macros () macro_import::slot &slot = imp.append (mod, flags); slot.offset = sec.u (); + /* FIXME: Re-enable or fix after root causing. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" + dump (dumper::MACRO) && dump ("Read %s macro %s%s%s %I at %u", imp.length () > 1 ? "add" : "new", @@ -16931,6 +16942,8 @@ module_state::install_macros () exp.def = cur; dump (dumper::MACRO) && dump ("Saving current #define %I", identifier (node)); + +#pragma GCC diagnostic pop } } -- cgit v1.1 From dee00bf6894be0cabb8f263c993357a6f8444f8b Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 7 Jul 2021 20:02:18 -0400 Subject: c++: Fix noexcept with unevaluated operand [PR101087] It sounds plausible that this assert int f(); static_assert(noexcept(sizeof(f()))); should pass: sizeof produces a std::size_t and its operand is not evaluated, so it can't throw. noexcept should only evaluate to false for potentially evaluated operands. Therefore I think that check_noexcept_r shouldn't walk into operands of sizeof/decltype/ alignof/typeof. PR c++/101087 gcc/cp/ChangeLog: * cp-tree.h (unevaluated_p): New. * except.c (check_noexcept_r): Use it. Don't walk into unevaluated operands. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/noexcept70.C: New test. --- gcc/cp/cp-tree.h | 13 +++++++++++++ gcc/cp/except.c | 9 ++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b450157..d4810c0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8465,6 +8465,19 @@ is_constrained_auto (const_tree t) return is_auto (t) && PLACEHOLDER_TYPE_CONSTRAINTS_INFO (t); } +/* True if CODE, a tree code, denotes a tree whose operand is not evaluated + as per [expr.context], i.e., an operand to sizeof, typeof, decltype, or + alignof. */ + +inline bool +unevaluated_p (tree_code code) +{ + return (code == DECLTYPE_TYPE + || code == ALIGNOF_EXPR + || code == SIZEOF_EXPR + || code == NOEXCEPT_EXPR); +} + /* RAII class to push/pop the access scope for T. */ struct push_access_scope_guard diff --git a/gcc/cp/except.c b/gcc/cp/except.c index a8cea53..a8acbc4 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1033,12 +1033,15 @@ check_handlers (tree handlers) expression whose type is a polymorphic class type (10.3). */ static tree -check_noexcept_r (tree *tp, int * /*walk_subtrees*/, void * /*data*/) +check_noexcept_r (tree *tp, int *walk_subtrees, void *) { tree t = *tp; enum tree_code code = TREE_CODE (t); - if ((code == CALL_EXPR && CALL_EXPR_FN (t)) - || code == AGGR_INIT_EXPR) + + if (unevaluated_p (code)) + *walk_subtrees = false; + else if ((code == CALL_EXPR && CALL_EXPR_FN (t)) + || code == AGGR_INIT_EXPR) { /* We can only use the exception specification of the called function for determining the value of a noexcept expression; we can't use -- cgit v1.1 From 79d3378c7d73814442eb468c562ab8aa572f9c43 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Thu, 8 Jul 2021 16:36:15 -0600 Subject: Move warning suppression to the ultimate callee. Resolves: PR bootstrap/101372 - -Warray-bounds in gcc/cp/module.cc causing bootstrap failure gcc/cp/ChangeLog: PR bootstrap/101372 * module.cc (identifier): Suppress warning. (module_state::read_macro_maps): Remove warning suppression. (module_state::install_macros): Ditto. --- gcc/cp/module.cc | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 8a890c1..ccbde29 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -274,7 +274,14 @@ static inline cpp_hashnode *cpp_node (tree id) static inline tree identifier (const cpp_hashnode *node) { + /* HT_NODE() expands to node->ident that HT_IDENT_TO_GCC_IDENT() + then subtracts a nonzero constant, deriving a pointer to + a different member than ident. That's strictly undefined + and detected by -Warray-bounds. Suppress it. See PR 101372. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" return HT_IDENT_TO_GCC_IDENT (HT_NODE (const_cast (node))); +#pragma GCC diagnostic pop } /* Id for dumping module information. */ @@ -16301,18 +16308,11 @@ module_state::read_macro_maps () } if (count) sec.set_overrun (); - - /* FIXME: Re-enable or fix after root causing. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Warray-bounds" - dump (dumper::LOCATION) && dump ("Macro:%u %I %u/%u*2 locations [%u,%u)", ix, identifier (node), runs, n_tokens, MAP_START_LOCATION (macro), MAP_START_LOCATION (macro) + n_tokens); - -#pragma GCC diagnostic pop } location_t lwm = sec.u (); macro_locs.first = lwm - slurp->loc_deltas.second; @@ -16918,10 +16918,6 @@ module_state::install_macros () macro_import::slot &slot = imp.append (mod, flags); slot.offset = sec.u (); - /* FIXME: Re-enable or fix after root causing. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Warray-bounds" - dump (dumper::MACRO) && dump ("Read %s macro %s%s%s %I at %u", imp.length () > 1 ? "add" : "new", @@ -16942,8 +16938,6 @@ module_state::install_macros () exp.def = cur; dump (dumper::MACRO) && dump ("Saving current #define %I", identifier (node)); - -#pragma GCC diagnostic pop } } -- cgit v1.1 From fdc4d2a516d042bc9a6936fad3f887aff353a296 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 9 Jul 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 31deb04..4386e5d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,24 @@ +2021-07-08 Martin Sebor + + PR bootstrap/101372 + * module.cc (identifier): Suppress warning. + (module_state::read_macro_maps): Remove warning suppression. + (module_state::install_macros): Ditto. + +2021-07-08 Marek Polacek + + PR c++/101087 + * cp-tree.h (unevaluated_p): New. + * except.c (check_noexcept_r): Use it. Don't walk into + unevaluated operands. + +2021-07-08 Martin Sebor + + PR bootstrap/101374 + * module.cc (module_state::read_macro_maps): Temporarily disable + -Warray-bounds. + (module_state::install_macros): Same. + 2021-07-06 Martin Sebor * error.c (cp_printer): Remove support for %G and %K. -- cgit v1.1 From f53e66019df819f55d424cc56f8b0ea81c074b55 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 9 Jul 2021 10:20:22 -0400 Subject: c++: find_template_parameters and TEMPLATE_DECLs [PR101247] r12-1989 fixed the testcase in the PR, but unfortunately the fix is buggy: it breaks the case where the common template between the TEMPLATE_DECL t and ctx_parms is the innermost template (as in concepts-memtmpl5.C below). This can be fixed by instead passing the TREE_TYPE of ctmpl to common_enclosing_class when ctmpl is a class template. But even after that's fixed, the analogous case where the innermost template is a partial specialization is still broken (as in concepts-memtmpl5a.C below), because ctmpl is always a primary template. So this patch instead takes a diferent approach that doesn't rely on ctx_parms at all: when looking for the template parameters of a TEMPLATE_DECL that are shared with the current template context, just walk its DECL_CONTEXT. As long as the template is not overly general (e.g. we didn't pass it through most_general_template), this should give us exactly what we want, since if a TEMPLATE_DECL can be referred to from some template context then the template parameters it uses must all be in-scope and contained in its DECL_CONTEXT. This effectively makes us treat TEMPLATE_DECLs more similarly to other _DECLs (whose DECL_CONTEXT we also walk). PR c++/101247 gcc/cp/ChangeLog: * pt.c (any_template_parm_r) : Just walk the DECL_CONTEXT. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-memtmpl4.C: Uncomment the commented out example, which we now handle correctly. * g++.dg/cpp2a/concepts-memtmpl5.C: New test. * g++.dg/cpp2a/concepts-memtmpl5a.C: New test. --- gcc/cp/pt.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7e56ccf..dc0f0b7 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10728,15 +10728,11 @@ any_template_parm_r (tree t, void *data) break; case TEMPLATE_DECL: - { - /* If T is a member template that shares template parameters with - ctx_parms, we need to mark all those parameters for mapping. */ - if (tree ctmpl = TREE_TYPE (INNERMOST_TEMPLATE_PARMS (ftpi->ctx_parms))) - if (tree com = common_enclosing_class (DECL_CONTEXT (t), - DECL_CONTEXT (ctmpl))) - if (tree ti = CLASSTYPE_TEMPLATE_INFO (com)) - WALK_SUBTREE (TI_ARGS (ti)); - } + /* If T is a member template that shares template parameters with + ctx_parms, we need to mark all those parameters for mapping. + To that end, it should suffice to just walk the DECL_CONTEXT of + the template (assuming the template is not overly general). */ + WALK_SUBTREE (DECL_CONTEXT (t)); break; case LAMBDA_EXPR: -- cgit v1.1 From 2c699fd29829cd6115f78238dab7cab74f0a5009 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 9 Jul 2021 10:20:25 -0400 Subject: c++: requires-expr with dependent extra args [PR101181] Here we're crashing ultimately because the mechanism for delaying substitution into a requires-expression (and constexpr if and pack expansions) doesn't expect to see dependent args. But we end up capturing dependent args here during substitution into the default template argument as part of coerce_template_parms for the dependent specialization p. This patch enables the commented out code in add_extra_args for handling this situation. This isn't needed for pack expansions (as the accompanying comment points out), and it doesn't seem strictly necessary for constexpr if either, but for requires-expressions delaying even dependent substitution is important for ensuring we don't evaluate requirements out of order. It turns out we also need to make a copy of the arguments when capturing them so that coerce_template_parms doesn't later add to them and form an unexpected cycle (REQUIRES_EXPR_EXTRA_ARGS (t) would indirectly point to t). We also need to make tsubst_template_args handle missing template arguments, since the arguments we capture from coerce_template_parms and are incomplete at that point. PR c++/101181 gcc/cp/ChangeLog: * constraint.cc (tsubst_requires_expr): Pass complain/in_decl to add_extra_args. * cp-tree.h (add_extra_args): Add complain/in_decl parameters. * pt.c (build_extra_args): Make a copy of args. (add_extra_args): Add complain/in_decl parameters. Enable the code for handling the case where the extra arguments are dependent. (tsubst_pack_expansion): Pass complain/in_decl to add_extra_args. (tsubst_template_args): Handle missing template arguments. (tsubst_expr) : Pass complain/in_decl to add_extra_args. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-requires26.C: New test. * g++.dg/cpp2a/lambda-uneval16.C: New test. --- gcc/cp/constraint.cc | 3 ++- gcc/cp/cp-tree.h | 2 +- gcc/cp/pt.c | 31 +++++++++++++++---------------- 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 99d3ccc..4ee5215 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -2266,7 +2266,8 @@ tsubst_requires_expr (tree t, tree args, sat_info info) /* A requires-expression is an unevaluated context. */ cp_unevaluated u; - args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args); + args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args, + info.complain, info.in_decl); if (processing_template_decl) { /* We're partially instantiating a generic lambda. Substituting into diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d4810c0..b1cf44e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7291,7 +7291,7 @@ extern void add_mergeable_specialization (bool is_decl, bool is_alias, tree outer, unsigned); extern tree add_to_template_args (tree, tree); extern tree add_outermost_template_args (tree, tree); -extern tree add_extra_args (tree, tree); +extern tree add_extra_args (tree, tree, tsubst_flags_t, tree); extern tree build_extra_args (tree, tree, tsubst_flags_t); /* in rtti.c */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index dc0f0b7..cf0ce77 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12907,7 +12907,9 @@ extract_local_specs (tree pattern, tsubst_flags_t complain) tree build_extra_args (tree pattern, tree args, tsubst_flags_t complain) { - tree extra = args; + /* Make a copy of the extra arguments so that they won't get changed + out from under us. */ + tree extra = copy_template_args (args); if (local_specializations) if (tree locals = extract_local_specs (pattern, complain)) extra = tree_cons (NULL_TREE, extra, locals); @@ -12918,7 +12920,7 @@ build_extra_args (tree pattern, tree args, tsubst_flags_t complain) normal template args to ARGS. */ tree -add_extra_args (tree extra, tree args) +add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl) { if (extra && TREE_CODE (extra) == TREE_LIST) { @@ -12938,20 +12940,14 @@ add_extra_args (tree extra, tree args) gcc_assert (!TREE_PURPOSE (extra)); extra = TREE_VALUE (extra); } -#if 1 - /* I think we should always be able to substitute dependent args into the - pattern. If that turns out to be incorrect in some cases, enable the - alternate code (and add complain/in_decl parms to this function). */ - gcc_checking_assert (!uses_template_parms (extra)); -#else - if (!uses_template_parms (extra)) + if (uses_template_parms (extra)) { - gcc_unreachable (); + /* This can happen after dependent substitution into a + requires-expr or a lambda that uses constexpr if. */ extra = tsubst_template_args (extra, args, complain, in_decl); args = add_outermost_template_args (args, extra); } else -#endif args = add_to_template_args (extra, args); return args; } @@ -12977,7 +12973,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, pattern = PACK_EXPANSION_PATTERN (t); /* Add in any args remembered from an earlier partial instantiation. */ - args = add_extra_args (PACK_EXPANSION_EXTRA_ARGS (t), args); + args = add_extra_args (PACK_EXPANSION_EXTRA_ARGS (t), args, complain, in_decl); levels = TMPL_ARGS_DEPTH (args); @@ -13349,7 +13345,9 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl) tree orig_arg = TREE_VEC_ELT (t, i); tree new_arg; - if (TREE_CODE (orig_arg) == TREE_VEC) + if (!orig_arg) + new_arg = NULL_TREE; + else if (TREE_CODE (orig_arg) == TREE_VEC) new_arg = tsubst_template_args (orig_arg, args, complain, in_decl); else if (PACK_EXPANSION_P (orig_arg)) { @@ -13399,8 +13397,9 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl) } for (i = 0, out = 0; i < len; i++) { - if ((PACK_EXPANSION_P (TREE_VEC_ELT (orig_t, i)) - || ARGUMENT_PACK_P (TREE_VEC_ELT (orig_t, i))) + tree orig_arg = TREE_VEC_ELT (orig_t, i); + if (orig_arg + && (PACK_EXPANSION_P (orig_arg) || ARGUMENT_PACK_P (orig_arg)) && TREE_CODE (elts[i]) == TREE_VEC) { int idx; @@ -18428,7 +18427,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t); IF_STMT_CONSTEVAL_P (stmt) = IF_STMT_CONSTEVAL_P (t); if (IF_STMT_CONSTEXPR_P (t)) - args = add_extra_args (IF_STMT_EXTRA_ARGS (t), args); + args = add_extra_args (IF_STMT_EXTRA_ARGS (t), args, complain, in_decl); tmp = RECUR (IF_COND (t)); tmp = finish_if_stmt_cond (tmp, stmt); if (IF_STMT_CONSTEXPR_P (t) -- cgit v1.1 From 0d5db79a61af150cba48612c9fbc3267262adb93 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Wed, 23 Jun 2021 08:13:22 +0100 Subject: coroutines: Fix a typo in rewriting the function. When amending the function re-write code, I made a typo in the block connections. This has not shown up in any test fails (as far as can be seen) but is a regression in debug info. Fixed thus. Signed-off-by: Iain Sandoe gcc/cp/ChangeLog: * coroutines.cc (coro_rewrite_function_body): Connect the replacement function block to the block nest correctly. --- gcc/cp/coroutines.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index a1b0b31..f5ae2d6 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4055,8 +4055,8 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, BIND_EXPR_BLOCK (first) = replace_blk; /* The top block has one child, so far, and we have now got a superblock. */ - BLOCK_SUPERCONTEXT (block) = top_block; - BLOCK_SUBBLOCKS (top_block) = block; + BLOCK_SUPERCONTEXT (replace_blk) = top_block; + BLOCK_SUBBLOCKS (top_block) = replace_blk; } /* Wrap the function body in a try {} catch (...) {} block, if exceptions -- cgit v1.1 From d5b1bb0d197f9141a0f0e510f8d1b598c3df9552 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Wed, 7 Jul 2021 19:56:20 +0100 Subject: coroutines: Factor code. Match original source location in helpers [NFC]. This is primarily a source code refactoring, the only change is to ensure that the outlined functions are marked to begin at the same line as the original. Otherwise, they get the default (which seems to be input_location, which corresponds to the closing brace at the point that this is done). Having the source location point to that confuses some debuggers. This is a contributory fix to: PR c++/99215 - coroutines: debugging with gdb Signed-off-by: Iain Sandoe gcc/cp/ChangeLog: * coroutines.cc (build_actor_fn): Move common code to act_des_fn. (build_destroy_fn): Likewise. (act_des_fn): Build the void return here. Ensure that the source location matches the original function. --- gcc/cp/coroutines.cc | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index f5ae2d6..54ffdc8 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2155,13 +2155,6 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* One param, the coro frame pointer. */ tree actor_fp = DECL_ARGUMENTS (actor); - /* A void return. */ - tree resdecl = build_decl (loc, RESULT_DECL, 0, void_type_node); - DECL_ARTIFICIAL (resdecl) = 1; - DECL_IGNORED_P (resdecl) = 1; - DECL_RESULT (actor) = resdecl; - DECL_COROUTINE_P (actor) = 1; - /* We have a definition here. */ TREE_STATIC (actor) = 1; @@ -2532,15 +2525,8 @@ build_destroy_fn (location_t loc, tree coro_frame_type, tree destroy, /* One param, the coro frame pointer. */ tree destr_fp = DECL_ARGUMENTS (destroy); - /* A void return. */ - tree resdecl = build_decl (loc, RESULT_DECL, 0, void_type_node); - DECL_ARTIFICIAL (resdecl) = 1; - DECL_IGNORED_P (resdecl) = 1; - DECL_RESULT (destroy) = resdecl; - /* We have a definition here. */ TREE_STATIC (destroy) = 1; - DECL_COROUTINE_P (destroy) = 1; tree destr_outer = push_stmt_list (); current_stmt_tree ()->stmts_are_full_exprs_p = 1; @@ -4000,15 +3986,19 @@ static tree act_des_fn (tree orig, tree fn_type, tree coro_frame_ptr, const char* name) { tree fn_name = get_fn_local_identifier (orig, name); + location_t loc = DECL_SOURCE_LOCATION (orig); tree fn = build_lang_decl (FUNCTION_DECL, fn_name, fn_type); DECL_CONTEXT (fn) = DECL_CONTEXT (orig); + DECL_SOURCE_LOCATION (fn) = loc; DECL_ARTIFICIAL (fn) = true; DECL_INITIAL (fn) = error_mark_node; + tree id = get_identifier ("frame_ptr"); tree fp = build_lang_decl (PARM_DECL, id, coro_frame_ptr); DECL_CONTEXT (fp) = fn; DECL_ARG_TYPE (fp) = type_passed_as (coro_frame_ptr); DECL_ARGUMENTS (fn) = fp; + /* Copy selected attributes from the original function. */ TREE_USED (fn) = TREE_USED (orig); if (DECL_SECTION_NAME (orig)) @@ -4020,6 +4010,17 @@ act_des_fn (tree orig, tree fn_type, tree coro_frame_ptr, const char* name) DECL_USER_ALIGN (fn) = DECL_USER_ALIGN (orig); /* Apply attributes from the original fn. */ DECL_ATTRIBUTES (fn) = copy_list (DECL_ATTRIBUTES (orig)); + + /* A void return. */ + tree resdecl = build_decl (loc, RESULT_DECL, 0, void_type_node); + DECL_CONTEXT (resdecl) = fn; + DECL_ARTIFICIAL (resdecl) = 1; + DECL_IGNORED_P (resdecl) = 1; + DECL_RESULT (fn) = resdecl; + + /* This is a coroutine component. */ + DECL_COROUTINE_P (fn) = 1; + return fn; } -- cgit v1.1 From ddd25bd1a7c8f456bc914e34b77d43f39a1062d4 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 9 Jul 2021 13:50:01 -0400 Subject: c++: concepts TS and explicit specialization [PR101098] duplicate_decls was not recognizing the explicit specialization as matching the implicit specialization of g because function_requirements_equivalent_p was seeing the C constraint on the implicit one and not on the explicit. PR c++/101098 gcc/cp/ChangeLog: * decl.c (function_requirements_equivalent_p): Only compare trailing requirements on a specialization. gcc/testsuite/ChangeLog: * g++.dg/concepts/explicit-spec1.C: New test. --- gcc/cp/decl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index ebe1318..0df689b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -955,7 +955,9 @@ static bool function_requirements_equivalent_p (tree newfn, tree oldfn) { /* In the concepts TS, the combined constraints are compared. */ - if (cxx_dialect < cxx20) + if (cxx_dialect < cxx20 + && (DECL_TEMPLATE_SPECIALIZATION (newfn) + <= DECL_TEMPLATE_SPECIALIZATION (oldfn))) { tree ci1 = get_constraints (oldfn); tree ci2 = get_constraints (newfn); -- cgit v1.1 From ef2ace642a1ba795235c542b728cb83c73dfce74 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 10 Jul 2021 00:16:53 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4386e5d..351476d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,45 @@ +2021-07-09 Jason Merrill + + PR c++/101098 + * decl.c (function_requirements_equivalent_p): Only compare + trailing requirements on a specialization. + +2021-07-09 Iain Sandoe + + * coroutines.cc (build_actor_fn): Move common code to + act_des_fn. + (build_destroy_fn): Likewise. + (act_des_fn): Build the void return here. Ensure that the + source location matches the original function. + +2021-07-09 Iain Sandoe + + * coroutines.cc + (coro_rewrite_function_body): Connect the replacement + function block to the block nest correctly. + +2021-07-09 Patrick Palka + + PR c++/101181 + * constraint.cc (tsubst_requires_expr): Pass complain/in_decl to + add_extra_args. + * cp-tree.h (add_extra_args): Add complain/in_decl parameters. + * pt.c (build_extra_args): Make a copy of args. + (add_extra_args): Add complain/in_decl parameters. Enable the + code for handling the case where the extra arguments are + dependent. + (tsubst_pack_expansion): Pass complain/in_decl to + add_extra_args. + (tsubst_template_args): Handle missing template arguments. + (tsubst_expr) : Pass complain/in_decl to + add_extra_args. + +2021-07-09 Patrick Palka + + PR c++/101247 + * pt.c (any_template_parm_r) : Just walk the + DECL_CONTEXT. + 2021-07-08 Martin Sebor PR bootstrap/101372 -- cgit v1.1 From b9119edc09e4660d772dea771578715858f7fbdb Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 9 Jul 2021 22:40:07 -0400 Subject: c++: 'new T[N]' and SFINAE [PR82110] Here we're failing to treat 'new T[N]' as erroneous in a SFINAE context when T isn't default constructible because expand_aggr_init_1 doesn't communicate to build_aggr_init (its only SFINAE caller) whether the initialization was actually successful. To fix this, this patch makes expand_aggr_init_1 and its subroutine expand_default_init return true on success, false on failure so that build_aggr_init can properly return error_mark_node on failure. PR c++/82110 gcc/cp/ChangeLog: * init.c (build_aggr_init): Return error_mark_node if expand_aggr_init_1 returns false. (expand_default_init): Change return type to bool. Return false on error, true on success. (expand_aggr_init_1): Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/pr78765.C: Expect another conversion failure diagnostic. * g++.dg/template/sfinae14.C: Flip incorrect assertion. * g++.dg/cpp2a/concepts-requires27.C: New test. --- gcc/cp/init.c | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 88f6f90..d47e405 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -39,8 +39,8 @@ along with GCC; see the file COPYING3. If not see static bool begin_init_stmts (tree *, tree *); static tree finish_init_stmts (bool, tree, tree); static void construct_virtual_base (tree, tree); -static void expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t); -static void expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t); +static bool expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t); +static bool expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t); static void perform_member_init (tree, tree); static int member_init_ok_or_else (tree, tree, tree); static void expand_virtual_init (tree, tree); @@ -1838,12 +1838,14 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain) is_global = begin_init_stmts (&stmt_expr, &compound_stmt); destroy_temps = stmts_are_full_exprs_p (); current_stmt_tree ()->stmts_are_full_exprs_p = 0; - expand_aggr_init_1 (TYPE_BINFO (type), exp, exp, - init, LOOKUP_NORMAL|flags, complain); + bool ok = expand_aggr_init_1 (TYPE_BINFO (type), exp, exp, + init, LOOKUP_NORMAL|flags, complain); stmt_expr = finish_init_stmts (is_global, stmt_expr, compound_stmt); current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps; TREE_READONLY (exp) = was_const; TREE_THIS_VOLATILE (exp) = was_volatile; + if (!ok) + return error_mark_node; if ((VAR_P (exp) || TREE_CODE (exp) == PARM_DECL) && TREE_SIDE_EFFECTS (stmt_expr) @@ -1854,7 +1856,7 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain) return stmt_expr; } -static void +static bool expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, tsubst_flags_t complain) { @@ -1889,6 +1891,9 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, happen for direct-initialization, too. */ init = digest_init (type, init, complain); + if (init == error_mark_node) + return false; + /* A CONSTRUCTOR of the target's type is a previously digested initializer, whether that happened just above or in cp_parser_late_parsing_nsdmi. @@ -1910,7 +1915,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init); TREE_SIDE_EFFECTS (init) = 1; finish_expr_stmt (init); - return; + return true; } if (init && TREE_CODE (init) != TREE_LIST @@ -1927,8 +1932,12 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, have already built up the constructor call so we could wrap it in an exception region. */; else - init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, - flags, complain | tf_no_cleanup); + { + init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, + flags, complain | tf_no_cleanup); + if (init == error_mark_node) + return false; + } if (TREE_CODE (init) == MUST_NOT_THROW_EXPR) /* We need to protect the initialization of a catch parm with a @@ -1944,7 +1953,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init); TREE_SIDE_EFFECTS (init) = 1; finish_expr_stmt (init); - return; + return true; } if (init == NULL_TREE) @@ -1982,6 +1991,8 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, &parms, binfo, flags, complain); base = fold_build_cleanup_point_expr (void_type_node, base); + if (complete == error_mark_node || base == error_mark_node) + return false; rval = build_if_in_charge (complete, base); } else @@ -1991,6 +2002,8 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, rval = build_special_member_call (exp, ctor_name, &parms, binfo, flags, complain); + if (rval == error_mark_node) + return false; } if (parms != NULL) @@ -2010,10 +2023,12 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, /* FIXME put back convert_to_void? */ if (TREE_SIDE_EFFECTS (rval)) finish_expr_stmt (rval); + + return true; } /* This function is responsible for initializing EXP with INIT - (if any). + (if any). Returns true on success, false on failure. BINFO is the binfo of the type for who we are performing the initialization. For example, if W is a virtual base class of A and B, @@ -2032,7 +2047,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, FLAGS is just passed to `build_new_method_call'. See that function for its description. */ -static void +static bool expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, tsubst_flags_t complain) { @@ -2058,7 +2073,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, if (init) finish_expr_stmt (init); gcc_assert (!cleanups); - return; + return true; } /* List-initialization from {} becomes value-initialization for non-aggregate @@ -2096,7 +2111,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, /* If we don't need to mess with the constructor at all, then we're done. */ if (! type_build_ctor_call (type)) - return; + return true; /* Otherwise fall through and call the constructor. */ init = NULL_TREE; @@ -2104,7 +2119,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, /* We know that expand_default_init can handle everything we want at this point. */ - expand_default_init (binfo, true_exp, exp, init, flags, complain); + return expand_default_init (binfo, true_exp, exp, init, flags, complain); } /* Report an error if TYPE is not a user-defined, class type. If -- cgit v1.1 From 269256f33c51222167ad461f775d5468bb5ecaf5 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 11 Jul 2021 00:16:35 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 351476d..39e5ec3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2021-07-10 Patrick Palka + + PR c++/82110 + * init.c (build_aggr_init): Return error_mark_node if + expand_aggr_init_1 returns false. + (expand_default_init): Change return type to bool. Return false + on error, true on success. + (expand_aggr_init_1): Likewise. + 2021-07-09 Jason Merrill PR c++/101098 -- cgit v1.1 From 8d75b8830e9dafb4e0c400c723653512adf40295 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 12 Jul 2021 16:35:18 -0400 Subject: c++: permit deduction guides at class scope [PR79501] This adds support for declaring (class-scope) deduction guides for a member class template. Fortunately it seems only a couple of changes are needed in order for the existing CTAD machinery to handle them properly: we need to make sure to give them a FUNCTION_TYPE instead of a METHOD_TYPE, and we need to avoid using a BASELINK when looking them up. PR c++/79501 PR c++/100983 gcc/cp/ChangeLog: * decl.c (grokfndecl): Don't require that deduction guides are declared at namespace scope. Check that class-scope deduction guides have the same access as the member class template. (grokdeclarator): Pretend class-scope deduction guides are static. * search.c (lookup_member): Don't use a BASELINK for (class-scope) deduction guides. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction92.C: New test. * g++.dg/cpp1z/class-deduction93.C: New test. * g++.dg/cpp1z/class-deduction94.C: New test. * g++.dg/cpp1z/class-deduction95.C: New test. --- gcc/cp/decl.c | 17 +++++++++++------ gcc/cp/search.c | 5 ++++- 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 0df689b..01d64a1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10042,12 +10042,6 @@ grokfndecl (tree ctype, if (deduction_guide_p (decl)) { - if (!DECL_NAMESPACE_SCOPE_P (decl)) - { - error_at (location, "deduction guide %qD must be declared at " - "namespace scope", decl); - return NULL_TREE; - } tree type = TREE_TYPE (DECL_NAME (decl)); if (in_namespace == NULL_TREE && CP_DECL_CONTEXT (decl) != CP_TYPE_CONTEXT (type)) @@ -10057,6 +10051,13 @@ grokfndecl (tree ctype, inform (location_of (type), " declared here"); return NULL_TREE; } + if (DECL_CLASS_SCOPE_P (decl) + && current_access_specifier != declared_access (TYPE_NAME (type))) + { + error_at (location, "deduction guide %qD must have the same access " + "as %qT", decl, type); + inform (location_of (type), " declared here"); + } if (funcdef_flag) error_at (location, "deduction guide %qD must not have a function body", decl); @@ -12037,6 +12038,10 @@ grokdeclarator (const cp_declarator *declarator, storage_class = declspecs->storage_class; if (storage_class == sc_static) staticp = 1 + (decl_context == FIELD); + else if (decl_context == FIELD && sfk == sfk_deduction_guide) + /* Treat class-scope deduction guides as static member functions + so that they get a FUNCTION_TYPE instead of a METHOD_TYPE. */ + staticp = 2; if (virtualp) { diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 7b18368..af41bfe 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1226,7 +1226,10 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type, rval = error_mark_node; } - if (rval && is_overloaded_fn (rval)) + if (rval && is_overloaded_fn (rval) + /* Don't use a BASELINK for class-scope deduction guides since + they're not actually member functions. */ + && !dguide_name_p (name)) rval = build_baselink (rval_binfo, basetype_path, rval, (IDENTIFIER_CONV_OP_P (name) ? TREE_TYPE (name): NULL_TREE)); -- cgit v1.1 From 07bcbf9cc2a031ba5abcff368b452bfc99bf707e Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 13 Jul 2021 00:16:30 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 39e5ec3..dc57991 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2021-07-12 Patrick Palka + + PR c++/79501 + PR c++/100983 + * decl.c (grokfndecl): Don't require that deduction guides are + declared at namespace scope. Check that class-scope deduction + guides have the same access as the member class template. + (grokdeclarator): Pretend class-scope deduction guides are static. + * search.c (lookup_member): Don't use a BASELINK for (class-scope) + deduction guides. + 2021-07-10 Patrick Palka PR c++/82110 -- cgit v1.1 From a42f8120442cf3ba25d621bed857b5be19019d0c Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 13 Jul 2021 17:16:54 -0400 Subject: c++: constexpr array reference and value-initialization [PR101371] This PR gave me a hard time: I saw multiple issues starting with different revisions. But ultimately the root cause seems to be the following, and the attached patch fixes all issues I've found here. In cxx_eval_array_reference we create a new constexpr context for the CP_AGGREGATE_TYPE_P case, but we also have to create it for the non-aggregate case. In this test, we are evaluating ((B *)this)->a = rhs->a which means that we set ctx.object to ((B *)this)->a. Then we proceed to evaluate the initializer, rhs->a. For *rhs, we eval rhs, a PARM_DECL, for which we have (const B &) &c.arr[0] in the hash table. Then cxx_fold_indirect_ref gives us c.arr[0]. c is evaluated to {.arr={}} so c.arr is {}. Now we want c.arr[0], so we end up in cxx_eval_array_reference and since we're initializing from {}, we call build_value_init which gives us an AGGR_INIT_EXPR that calls 'constexpr B::B()'. Then we evaluate this AGGR_INIT_EXPR and since its first argument is dummy, we take ctx.object instead. But that is the wrong object, we're not initializing ((B *)this)->a here. And so we wound up with an initializer for A, and then crash in cxx_eval_component_reference: gcc_assert (DECL_CONTEXT (part) == TYPE_MAIN_VARIANT (TREE_TYPE (whole))); where DECL_CONTEXT (part) is B (as it should be) but the type of whole was A. So create a new object, if there already was one, and the element type is not a scalar. PR c++/101371 gcc/cp/ChangeLog: * constexpr.c (cxx_eval_array_reference): Create a new .object and .ctor for the non-aggregate non-scalar case too when value-initializing. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/constexpr-101371-2.C: New test. * g++.dg/cpp1y/constexpr-101371.C: New test. --- gcc/cp/constexpr.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 39787f3..31fa5b6 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3851,16 +3851,23 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, { tree empty_ctor = build_constructor (init_list_type_node, NULL); val = digest_init (elem_type, empty_ctor, tf_warning_or_error); + } + else + val = build_value_init (elem_type, tf_warning_or_error); + + if (!SCALAR_TYPE_P (elem_type)) + { new_ctx = *ctx; - new_ctx.object = t; + if (ctx->object) + /* If there was no object, don't add one: it could confuse us + into thinking we're modifying a const object. */ + new_ctx.object = t; new_ctx.ctor = build_constructor (elem_type, NULL); ctx = &new_ctx; } - else - val = build_value_init (elem_type, tf_warning_or_error); t = cxx_eval_constant_expression (ctx, val, lval, non_constant_p, overflow_p); - if (CP_AGGREGATE_TYPE_P (elem_type) && t != ctx->ctor) + if (!SCALAR_TYPE_P (elem_type) && t != ctx->ctor) free_constructor (ctx->ctor); return t; } -- 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/class.c | 4 +--- gcc/cp/coroutines.cc | 2 +- gcc/cp/cp-gimplify.c | 3 +-- gcc/cp/parser.c | 6 +----- gcc/cp/semantics.c | 3 +-- 5 files changed, 5 insertions(+), 13 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 33093e1..14db066 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2391,7 +2391,7 @@ struct find_final_overrider_data { /* The candidate overriders. */ tree candidates; /* Path to most derived. */ - vec path; + auto_vec path; }; /* Add the overrider along the current path to FFOD->CANDIDATES. @@ -2504,8 +2504,6 @@ find_final_overrider (tree derived, tree binfo, tree fn) dfs_walk_all (derived, dfs_find_final_overrider_pre, dfs_find_final_overrider_post, &ffod); - ffod.path.release (); - /* If there was no winner, issue an error message. */ if (!ffod.candidates || TREE_CHAIN (ffod.candidates)) return error_mark_node; diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 54ffdc8..712a5c0 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -3081,7 +3081,7 @@ process_conditional (var_nest_node *n, tree& vlist) { tree init = n->init; hash_map var_flags; - vec var_list = vNULL; + auto_vec var_list; tree new_then = push_stmt_list (); handle_nested_conditionals (n->then_cl, var_list, var_flags); new_then = pop_stmt_list (new_then); diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 00b7772..de37f2c 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -807,7 +807,7 @@ omp_cxx_notice_variable (struct cp_genericize_omp_taskreg *omp_ctx, tree decl) struct cp_genericize_data { hash_set *p_set; - vec bind_expr_stack; + auto_vec bind_expr_stack; struct cp_genericize_omp_taskreg *omp_ctx; tree try_block; bool no_sanitize_p; @@ -1582,7 +1582,6 @@ cp_genericize_tree (tree* t_p, bool handle_invisiref_parm_p) wtd.handle_invisiref_parm_p = handle_invisiref_parm_p; cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL); delete wtd.p_set; - wtd.bind_expr_stack.release (); if (sanitize_flags_p (SANITIZE_VPTR)) cp_ubsan_instrument_member_accesses (t_p); } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 93698aa..821ce17 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -35247,7 +35247,7 @@ cp_parser_objc_at_property_declaration (cp_parser *parser) /* Parse the optional attribute list. A list of parsed, but not verified, attributes. */ - vec prop_attr_list = vNULL; + auto_delete_vec prop_attr_list; location_t loc = cp_lexer_peek_token (parser->lexer)->location; cp_lexer_consume_token (parser->lexer); /* Eat '@property'. */ @@ -35423,10 +35423,6 @@ cp_parser_objc_at_property_declaration (cp_parser *parser) } cp_parser_consume_semicolon_at_end_of_statement (parser); - - while (!prop_attr_list.is_empty()) - delete prop_attr_list.pop (); - prop_attr_list.release (); } /* Parse an Objective-C++ @synthesize declaration. The syntax is: 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 bebd8e9da838c51a7f911985083d5a2b2498a23a Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 14 Jul 2021 15:37:30 -0400 Subject: c++: CTAD and forwarding references [PR88252] Here during CTAD we're incorrectly treating T&& as a forwarding reference even though T is a template parameter of the class template. This happens because the template parameter T in the out-of-line definition of the constructor doesn't have the flag TEMPLATE_TYPE_PARM_FOR_CLASS set, and during duplicate_decls the the redeclaration (which is in terms of this unflagged T) prevails. To fix this, we could perhaps be more consistent about setting the flag, but it appears we don't really need this flag to make the determination. Since the template parameters of an synthesized guide consist of the template parameters of the class template followed by those of the constructor (if any), it should suffice to look at the index of the template parameter to determine whether it comes from the class template or the constructor (template). This patch replaces the TEMPLATE_TYPE_PARM_FOR_CLASS flag with this approach. PR c++/88252 gcc/cp/ChangeLog: * cp-tree.h (TEMPLATE_TYPE_PARM_FOR_CLASS): Remove. * pt.c (push_template_decl): Remove TEMPLATE_TYPE_PARM_FOR_CLASS handling. (redeclare_class_template): Likewise. (forwarding_reference_p): Define. (maybe_adjust_types_for_deduction): Use it instead. Add 'tparms' parameter. (unify_one_argument): Pass tparms to maybe_adjust_types_for_deduction. (try_one_overload): Likewise. (unify): Likewise. (rewrite_template_parm): Remove TEMPLATE_TYPE_PARM_FOR_CLASS handling. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction96.C: New test. --- gcc/cp/cp-tree.h | 6 ---- gcc/cp/pt.c | 90 +++++++++++++++++++++++++++++++------------------------- 2 files changed, 50 insertions(+), 46 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b1cf44e..f4bcab5 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -443,7 +443,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; BLOCK_OUTER_CURLY_BRACE_P (in BLOCK) FOLD_EXPR_MODOP_P (*_FOLD_EXPR) IF_STMT_CONSTEXPR_P (IF_STMT) - TEMPLATE_TYPE_PARM_FOR_CLASS (TEMPLATE_TYPE_PARM) DECL_NAMESPACE_INLINE_P (in NAMESPACE_DECL) SWITCH_STMT_ALL_CASES_P (in SWITCH_STMT) REINTERPRET_CAST_P (in NOP_EXPR) @@ -5863,11 +5862,6 @@ enum auto_deduction_context adc_decomp_type /* Decomposition declaration initializer deduction */ }; -/* True if this type-parameter belongs to a class template, used by C++17 - class template argument deduction. */ -#define TEMPLATE_TYPE_PARM_FOR_CLASS(NODE) \ - (TREE_LANG_FLAG_0 (TEMPLATE_TYPE_PARM_CHECK (NODE))) - /* True iff this TEMPLATE_TYPE_PARM represents decltype(auto). */ #define AUTO_IS_DECLTYPE(NODE) \ (TYPE_LANG_FLAG_5 (TEMPLATE_TYPE_PARM_CHECK (NODE))) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index cf0ce77..c7bf7d4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -154,8 +154,8 @@ static void tsubst_enum (tree, tree, tree); static bool check_instantiated_args (tree, tree, tsubst_flags_t); static int check_non_deducible_conversion (tree, tree, int, int, struct conversion **, bool); -static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*, - tree); +static int maybe_adjust_types_for_deduction (tree, unification_kind_t, + tree*, tree*, tree); static int type_unification_real (tree, tree, tree, const tree *, unsigned int, int, unification_kind_t, vec **, @@ -5801,18 +5801,7 @@ push_template_decl (tree decl, bool is_friend) } else if (DECL_IMPLICIT_TYPEDEF_P (decl) && CLASS_TYPE_P (TREE_TYPE (decl))) - { - /* Class template, set TEMPLATE_TYPE_PARM_FOR_CLASS. */ - tree parms = INNERMOST_TEMPLATE_PARMS (current_template_parms); - for (int i = 0; i < TREE_VEC_LENGTH (parms); ++i) - { - tree t = TREE_VALUE (TREE_VEC_ELT (parms, i)); - if (TREE_CODE (t) == TYPE_DECL) - t = TREE_TYPE (t); - if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) - TEMPLATE_TYPE_PARM_FOR_CLASS (t) = true; - } - } + /* Class template. */; else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_ALIAS_P (decl)) /* alias-declaration */ @@ -6292,9 +6281,6 @@ redeclare_class_template (tree type, tree parms, tree cons) gcc_assert (DECL_CONTEXT (parm) == NULL_TREE); DECL_CONTEXT (parm) = tmpl; } - - if (TREE_CODE (parm) == TYPE_DECL) - TEMPLATE_TYPE_PARM_FOR_CLASS (TREE_TYPE (parm)) = true; } tree ci = get_constraints (tmpl); @@ -21709,6 +21695,41 @@ fn_type_unification (tree fn, return r; } +/* Returns true iff PARM is a forwarding reference in the context of + template argument deduction for TMPL. */ + +static bool +forwarding_reference_p (tree parm, tree tmpl) +{ + /* [temp.deduct.call], "A forwarding reference is an rvalue reference to a + cv-unqualified template parameter ..." */ + if (TYPE_REF_P (parm) + && TYPE_REF_IS_RVALUE (parm) + && TREE_CODE (TREE_TYPE (parm)) == TEMPLATE_TYPE_PARM + && cp_type_quals (TREE_TYPE (parm)) == TYPE_UNQUALIFIED) + { + parm = TREE_TYPE (parm); + /* [temp.deduct.call], "... that does not represent a template parameter + of a class template (during class template argument deduction)." */ + if (tmpl + && deduction_guide_p (tmpl) + && DECL_ARTIFICIAL (tmpl)) + { + /* Since the template parameters of a synthesized guide consist of + the template parameters of the class template followed by those of + the constructor (if any), we can tell if PARM represents a template + parameter of the class template by comparing its index with the + arity of the class template. */ + tree ctmpl = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (TREE_TYPE (tmpl))); + if (TEMPLATE_TYPE_IDX (parm) + < TREE_VEC_LENGTH (DECL_INNERMOST_TEMPLATE_PARMS (ctmpl))) + return false; + } + return true; + } + return false; +} + /* Adjust types before performing type deduction, as described in [temp.deduct.call] and [temp.deduct.conv]. The rules in these two sections are symmetric. PARM is the type of a function parameter @@ -21718,7 +21739,8 @@ fn_type_unification (tree fn, ARG_EXPR is the original argument expression, which may be null. */ static int -maybe_adjust_types_for_deduction (unification_kind_t strict, +maybe_adjust_types_for_deduction (tree tparms, + unification_kind_t strict, tree* parm, tree* arg, tree arg_expr) @@ -21741,10 +21763,7 @@ maybe_adjust_types_for_deduction (unification_kind_t strict, /* Core issue #873: Do the DR606 thing (see below) for these cases, too, but here handle it by stripping the reference from PARM rather than by adding it to ARG. */ - if (TYPE_REF_P (*parm) - && TYPE_REF_IS_RVALUE (*parm) - && TREE_CODE (TREE_TYPE (*parm)) == TEMPLATE_TYPE_PARM - && cp_type_quals (TREE_TYPE (*parm)) == TYPE_UNQUALIFIED + if (forwarding_reference_p (*parm, TPARMS_PRIMARY_TEMPLATE (tparms)) && TYPE_REF_P (*arg) && !TYPE_REF_IS_RVALUE (*arg)) *parm = TREE_TYPE (*parm); @@ -21781,17 +21800,10 @@ maybe_adjust_types_for_deduction (unification_kind_t strict, *arg = TYPE_MAIN_VARIANT (*arg); } - /* [14.8.2.1/3 temp.deduct.call], "A forwarding reference is an rvalue - reference to a cv-unqualified template parameter that does not represent a - template parameter of a class template (during class template argument - deduction (13.3.1.8)). If P is a forwarding reference and the argument is - an lvalue, the type "lvalue reference to A" is used in place of A for type - deduction. */ - if (TYPE_REF_P (*parm) - && TYPE_REF_IS_RVALUE (*parm) - && TREE_CODE (TREE_TYPE (*parm)) == TEMPLATE_TYPE_PARM - && !TEMPLATE_TYPE_PARM_FOR_CLASS (TREE_TYPE (*parm)) - && cp_type_quals (TREE_TYPE (*parm)) == TYPE_UNQUALIFIED + /* [temp.deduct.call], "If P is a forwarding reference and the argument is + an lvalue, the type 'lvalue reference to A' is used in place of A for + type deduction." */ + if (forwarding_reference_p (*parm, TPARMS_PRIMARY_TEMPLATE (tparms)) && (arg_expr ? lvalue_p (arg_expr) /* try_one_overload doesn't provide an arg_expr, but functions are always lvalues. */ @@ -22080,8 +22092,8 @@ unify_one_argument (tree tparms, tree targs, tree parm, tree arg, return unify_invalid (explain_p); } - arg_strict |= - maybe_adjust_types_for_deduction (strict, &parm, &arg, arg_expr); + arg_strict |= maybe_adjust_types_for_deduction (tparms, strict, + &parm, &arg, arg_expr); } else if ((TYPE_P (parm) || TREE_CODE (parm) == TEMPLATE_DECL) @@ -22750,7 +22762,8 @@ try_one_overload (tree tparms, else if (addr_p) arg = build_pointer_type (arg); - sub_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg, NULL); + sub_strict |= maybe_adjust_types_for_deduction (tparms, strict, + &parm, &arg, NULL_TREE); /* We don't copy orig_targs for this because if we have already deduced some template args from previous args, unify would complain when we @@ -23449,7 +23462,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, /* It should only be possible to get here for a call. */ gcc_assert (elt_strict & UNIFY_ALLOW_OUTER_LEVEL); elt_strict |= maybe_adjust_types_for_deduction - (DEDUCE_CALL, &elttype, &type, elt); + (tparms, DEDUCE_CALL, &elttype, &type, elt); elt = type; } @@ -28495,9 +28508,6 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level, tree oldtype = TREE_TYPE (olddecl); newtype = cxx_make_type (TREE_CODE (oldtype)); TYPE_MAIN_VARIANT (newtype) = newtype; - if (TREE_CODE (oldtype) == TEMPLATE_TYPE_PARM) - TEMPLATE_TYPE_PARM_FOR_CLASS (newtype) - = TEMPLATE_TYPE_PARM_FOR_CLASS (oldtype); } else { -- cgit v1.1 From c4fee1c646d52a9001a53fa0d4072db86b9be791 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 15 Jul 2021 00:16:54 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index dc57991..a80d236 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,38 @@ +2021-07-14 Patrick Palka + + PR c++/88252 + * cp-tree.h (TEMPLATE_TYPE_PARM_FOR_CLASS): Remove. + * pt.c (push_template_decl): Remove TEMPLATE_TYPE_PARM_FOR_CLASS + handling. + (redeclare_class_template): Likewise. + (forwarding_reference_p): Define. + (maybe_adjust_types_for_deduction): Use it instead. Add 'tparms' + parameter. + (unify_one_argument): Pass tparms to + maybe_adjust_types_for_deduction. + (try_one_overload): Likewise. + (unify): Likewise. + (rewrite_template_parm): Remove TEMPLATE_TYPE_PARM_FOR_CLASS + handling. + +2021-07-14 Jason Merrill + + * 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. + +2021-07-14 Marek Polacek + + PR c++/101371 + * constexpr.c (cxx_eval_array_reference): Create a new .object + and .ctor for the non-aggregate non-scalar case too when + value-initializing. + 2021-07-12 Patrick Palka PR c++/79501 -- cgit v1.1 From 0b7a11874d4eb428c18a91f38786032ce0e77a96 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 14 Jul 2021 17:10:49 -0400 Subject: c++: fix tree_contains_struct for C++ types [PR101095] Many of the types from cp-tree.def were only marked as having tree_common, when actually most of them have type_non_common. This broke g++.dg/modules/xtreme-header-2, as the modules code relies on tree_contains_struct to know what bits it needs to stream. We don't seem to use type_non_common for TYPE_ARGUMENT_PACK, so I bumped it down to TS_TYPE_COMMON. I tried doing the same in cp_tree_size, but that breaks without more extensive changes to tree_node_structure. Why do we need the init_ts function anyway? It seems redundant with tree_node_structure. PR c++/101095 gcc/cp/ChangeLog: * cp-objcp-common.c (cp_common_init_ts): Mark types as types. (cp_tree_size): Remove redundant entries. --- gcc/cp/cp-objcp-common.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 46b2248..ee25573 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -72,10 +72,13 @@ cp_tree_size (enum tree_code code) case DEFERRED_NOEXCEPT: return sizeof (tree_deferred_noexcept); case OVERLOAD: return sizeof (tree_overload); case STATIC_ASSERT: return sizeof (tree_static_assert); - case TYPE_ARGUMENT_PACK: - case TYPE_PACK_EXPANSION: return sizeof (tree_type_non_common); - case NONTYPE_ARGUMENT_PACK: - case EXPR_PACK_EXPANSION: return sizeof (tree_exp); +#if 0 + /* This would match cp_common_init_ts, but breaks GC because + tree_node_structure_for_code returns TS_TYPE_NON_COMMON for all + types. */ + case UNBOUND_CLASS_TEMPLATE: + case TYPE_ARGUMENT_PACK: return sizeof (tree_type_common); +#endif case ARGUMENT_PACK_SELECT: return sizeof (tree_argument_pack_select); case TRAIT_EXPR: return sizeof (tree_trait_expr); case LAMBDA_EXPR: return sizeof (tree_lambda_expr); @@ -456,13 +459,8 @@ cp_common_init_ts (void) /* Random new trees. */ MARK_TS_COMMON (BASELINK); - MARK_TS_COMMON (DECLTYPE_TYPE); MARK_TS_COMMON (OVERLOAD); MARK_TS_COMMON (TEMPLATE_PARM_INDEX); - MARK_TS_COMMON (TYPENAME_TYPE); - MARK_TS_COMMON (TYPEOF_TYPE); - MARK_TS_COMMON (UNBOUND_CLASS_TEMPLATE); - MARK_TS_COMMON (UNDERLYING_TYPE); /* New decls. */ MARK_TS_DECL_COMMON (TEMPLATE_DECL); @@ -472,10 +470,16 @@ cp_common_init_ts (void) MARK_TS_DECL_NON_COMMON (USING_DECL); /* New Types. */ + MARK_TS_TYPE_COMMON (UNBOUND_CLASS_TEMPLATE); + MARK_TS_TYPE_COMMON (TYPE_ARGUMENT_PACK); + + MARK_TS_TYPE_NON_COMMON (DECLTYPE_TYPE); + MARK_TS_TYPE_NON_COMMON (TYPENAME_TYPE); + MARK_TS_TYPE_NON_COMMON (TYPEOF_TYPE); + MARK_TS_TYPE_NON_COMMON (UNDERLYING_TYPE); MARK_TS_TYPE_NON_COMMON (BOUND_TEMPLATE_TEMPLATE_PARM); MARK_TS_TYPE_NON_COMMON (TEMPLATE_TEMPLATE_PARM); MARK_TS_TYPE_NON_COMMON (TEMPLATE_TYPE_PARM); - MARK_TS_TYPE_NON_COMMON (TYPE_ARGUMENT_PACK); MARK_TS_TYPE_NON_COMMON (TYPE_PACK_EXPANSION); /* Statements. */ -- cgit v1.1 From 7094a69bd62a14dfa311eaa2fea468f221c7c9f3 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 15 Jul 2021 18:53:20 +0200 Subject: c++: Optimize away NULLPTR_TYPE comparisons [PR101443] Comparisons of NULLPTR_TYPE operands cause all kinds of problems in the middle-end and in fold-const.c, various optimizations assume that if they see e.g. a non-equality comparison with one of the operands being INTEGER_CST and it is not INTEGRAL_TYPE_P (which has TYPE_{MIN,MAX}_VALUE), they can build_int_cst (type, 1) to find a successor. The following patch fixes it by making sure they don't appear in the IL, optimize them away at cp_fold time as all can be folded. Though, I've just noticed that clang++ rejects the non-equality comparisons instead, foo () > 0 with invalid operands to binary expression ('decltype(nullptr)' (aka 'nullptr_t') and 'int') and foo () > nullptr with invalid operands to binary expression ('decltype(nullptr)' (aka 'nullptr_t') and 'nullptr_t') Shall we reject those too, in addition or instead of parts of this patch? If so, wouldn't this patch be still useful for backports, I bet we don't want to start reject it on the release branches when we used to accept it. 2021-07-15 Jakub Jelinek PR c++/101443 * cp-gimplify.c (cp_fold): For comparisons with NULLPTR_TYPE operands, fold them right away to true or false. * g++.dg/cpp0x/nullptr46.C: New test. --- gcc/cp/cp-gimplify.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index de37f2c..ff0bff7 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -2423,6 +2423,32 @@ cp_fold (tree x) op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops); op1 = cp_fold_rvalue (TREE_OPERAND (x, 1)); + /* decltype(nullptr) has only one value, so optimize away all comparisons + with that type right away, keeping them in the IL causes troubles for + various optimizations. */ + if (COMPARISON_CLASS_P (org_x) + && TREE_CODE (TREE_TYPE (op0)) == NULLPTR_TYPE + && TREE_CODE (TREE_TYPE (op1)) == NULLPTR_TYPE) + { + switch (code) + { + case EQ_EXPR: + case LE_EXPR: + case GE_EXPR: + x = constant_boolean_node (true, TREE_TYPE (x)); + break; + case NE_EXPR: + case LT_EXPR: + case GT_EXPR: + x = constant_boolean_node (false, TREE_TYPE (x)); + break; + default: + gcc_unreachable (); + } + return omit_two_operands_loc (loc, TREE_TYPE (x), x, + op0, op1); + } + if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1)) { if (op0 == error_mark_node || op1 == error_mark_node) -- cgit v1.1 From d97d71a1989e9ee8e1b8563b351c42b7732da108 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 16 Jul 2021 00:16:25 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a80d236..0e2139a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2021-07-15 Jakub Jelinek + + PR c++/101443 + * cp-gimplify.c (cp_fold): For comparisons with NULLPTR_TYPE + operands, fold them right away to true or false. + +2021-07-15 Jason Merrill + + PR c++/101095 + * cp-objcp-common.c (cp_common_init_ts): Mark types as types. + (cp_tree_size): Remove redundant entries. + 2021-07-14 Patrick Palka PR c++/88252 -- cgit v1.1 From e32234536f361796e7cad8ed69a1c0bb46ee55de Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Thu, 15 Jul 2021 18:45:49 -0400 Subject: c++: Don't hide narrowing errors in system headers Jonathan pointed me at this issue where constexpr unsigned f() { constexpr int n = -1; return unsigned{n}; } is accepted in system headers, despite the narrowing conversion from a constant. I suspect that whereas narrowing warnings should be disabled, ill-formed narrowing of constants should be a hard error (which can still be disabled by -Wno-narrowing). gcc/cp/ChangeLog: * typeck2.c (check_narrowing): Don't suppress the pedantic error in system headers. libstdc++-v3/ChangeLog: * testsuite/20_util/ratio/operations/ops_overflow_neg.cc: Add dg-error. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/Wnarrowing2.C: New test. * g++.dg/cpp1y/Wnarrowing2.h: New test. --- gcc/cp/typeck2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc/cp') diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 6679e24..dcfdff2 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -986,6 +986,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain, { int savederrorcount = errorcount; global_dc->pedantic_errors = 1; + auto s = make_temp_override (global_dc->dc_warn_system_headers, true); pedwarn (loc, OPT_Wnarrowing, "narrowing conversion of %qE from %qH to %qI", init, ftype, type); -- cgit v1.1 From d04b0c75794545f1f7a942764285e21eaf2915a1 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 16 Jul 2021 16:21:10 -0400 Subject: c++: covariant reference return types [PR99664] This implements the wording changes of CWG 960 which clarifies that two reference types are covariant only if they're both lvalue references or both rvalue references. DR 960 PR c++/99664 gcc/cp/ChangeLog: * search.c (check_final_overrider): Compare TYPE_REF_IS_RVALUE when the return types are references. gcc/testsuite/ChangeLog: * g++.dg/inherit/covariant23.C: New test. --- gcc/cp/search.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/search.c b/gcc/cp/search.c index af41bfe..943671a 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1948,7 +1948,13 @@ check_final_overrider (tree overrider, tree basefn) fail = !INDIRECT_TYPE_P (base_return); if (!fail) { - fail = cp_type_quals (base_return) != cp_type_quals (over_return); + if (cp_type_quals (base_return) != cp_type_quals (over_return)) + fail = 1; + + if (TYPE_REF_P (base_return) + && (TYPE_REF_IS_RVALUE (base_return) + != TYPE_REF_IS_RVALUE (over_return))) + fail = 1; base_return = TREE_TYPE (base_return); over_return = TREE_TYPE (over_return); -- cgit v1.1 From a8b3861496bffae8b813ea196c1c5b27f79fbe69 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 16 Jul 2021 16:21:13 -0400 Subject: c++: alias CTAD in unevaluated context [PR101233] This is the alias CTAD version of the CTAD bug PR93248, and the fix is the same: clear cp_unevaluated_operand so that the entire chain of DECL_ARGUMENTS gets substituted. PR c++/101233 gcc/cp/ChangeLog: * pt.c (alias_ctad_tweaks): Clear cp_unevaluated_operand for substituting DECL_ARGUMENTS. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-alias10.C: New test. --- gcc/cp/pt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index c7bf7d4..94ca3bc 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -29097,7 +29097,13 @@ alias_ctad_tweaks (tree tmpl, tree uguides) /* Substitute the deduced arguments plus the rewritten template parameters into f to get g. This covers the type, copyness, guideness, and explicit-specifier. */ - tree g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain); + tree g; + { + /* Parms are to have DECL_CHAIN tsubsted, which would be skipped + if cp_unevaluated_operand. */ + cp_evaluated ev; + g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain); + } if (g == error_mark_node) continue; DECL_USE_TEMPLATE (g) = 0; -- cgit v1.1 From 87277b6a04486b606761b86dbcfbc9a4b6871f4c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 17 Jul 2021 00:16:31 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0e2139a..0c4734f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2021-07-16 Patrick Palka + + PR c++/101233 + * pt.c (alias_ctad_tweaks): Clear cp_unevaluated_operand for + substituting DECL_ARGUMENTS. + +2021-07-16 Patrick Palka + + DR 960 + PR c++/99664 + * search.c (check_final_overrider): Compare TYPE_REF_IS_RVALUE + when the return types are references. + +2021-07-16 Marek Polacek + + * typeck2.c (check_narrowing): Don't suppress the pedantic error + in system headers. + 2021-07-15 Jakub Jelinek PR c++/101443 -- cgit v1.1 From 237ab3ee49e2f3110accfcc03b6c0df8b4889f15 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Thu, 8 Jul 2021 09:42:49 +0100 Subject: coroutines: Adjust outlined function names [PR95520]. The mechanism used to date for uniquing the coroutine helper functions (actor, destroy) was over-complicating things and leading to the noted PR and also difficulties in setting breakpoints on these functions (so this will help PR99215 as well). This implementation delegates the adjustment to the mangling to write_encoding() which necessitates some book-keeping so that it is possible to determine which of the coroutine helper names is to be mangled. Signed-off-by: Iain Sandoe PR c++/95520 - [coroutines] __builtin_FUNCTION() returns mangled .actor instead of original function name PR c++/95520 gcc/cp/ChangeLog: * coroutines.cc (struct coroutine_info): Add fields for actor and destroy function decls. (to_ramp): New. (coro_get_ramp_function): New. (coro_get_actor_function): New. (coro_get_destroy_function): New. (act_des_fn): Set up mapping between ramp, actor and destroy functions. (morph_fn_to_coro): Adjust interface to the builder for helper function decls. * cp-tree.h (DECL_ACTOR_FN, DECL_DESTROY_FN, DECL_RAMP_FN, JOIN_STR): New. * mangle.c (write_encoding): Handle coroutine helpers. (write_unqualified_name): Handle lambda coroutine helpers. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr95520.C: New test. --- gcc/cp/coroutines.cc | 87 ++++++++++++++++++++++++++++++++++++++++++++-------- gcc/cp/cp-tree.h | 22 +++++++++++++ gcc/cp/mangle.c | 19 ++++++++++-- 3 files changed, 114 insertions(+), 14 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 712a5c0..47c79e5 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -82,11 +82,13 @@ static bool coro_promise_type_found_p (tree, location_t); struct GTY((for_user)) coroutine_info { tree function_decl; /* The original function decl. */ - tree promise_type; /* The cached promise type for this function. */ - tree handle_type; /* The cached coroutine handle for this function. */ - tree self_h_proxy; /* A handle instance that is used as the proxy for the - one that will eventually be allocated in the coroutine - frame. */ + tree actor_decl; /* The synthesized actor function. */ + tree destroy_decl; /* The synthesized destroy function. */ + tree promise_type; /* The cached promise type for this function. */ + tree handle_type; /* The cached coroutine handle for this function. */ + tree self_h_proxy; /* A handle instance that is used as the proxy for the + one that will eventually be allocated in the coroutine + frame. */ tree promise_proxy; /* Likewise, a proxy promise instance. */ tree return_void; /* The expression for p.return_void() if it exists. */ location_t first_coro_keyword; /* The location of the keyword that made this @@ -526,6 +528,46 @@ coro_promise_type_found_p (tree fndecl, location_t loc) return true; } +/* Map from actor or destroyer to ramp. */ +static GTY(()) hash_map *to_ramp; + +/* Given a tree that is an actor or destroy, find the ramp function. */ + +tree +coro_get_ramp_function (tree decl) +{ + if (!to_ramp) + return NULL_TREE; + tree *p = to_ramp->get (decl); + if (p) + return *p; + return NULL_TREE; +} + +/* Given the DECL for a ramp function (the user's original declaration) return + the actor function if it has been defined. */ + +tree +coro_get_actor_function (tree decl) +{ + if (coroutine_info *info = get_coroutine_info (decl)) + return info->actor_decl; + + return NULL_TREE; +} + +/* Given the DECL for a ramp function (the user's original declaration) return + the destroy function if it has been defined. */ + +tree +coro_get_destroy_function (tree decl) +{ + if (coroutine_info *info = get_coroutine_info (decl)) + return info->destroy_decl; + + return NULL_TREE; +} + /* These functions assumes that the caller has verified that the state for the decl has been initialized, we try to minimize work here. */ @@ -3979,15 +4021,23 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) return NULL_TREE; } -/* Build, return FUNCTION_DECL node with its coroutine frame pointer argument - for either actor or destroy functions. */ +/* Build, return FUNCTION_DECL node based on ORIG with a type FN_TYPE which has + a single argument of type CORO_FRAME_PTR. Build the actor function if + ACTOR_P is true, otherwise the destroy. */ static tree -act_des_fn (tree orig, tree fn_type, tree coro_frame_ptr, const char* name) +coro_build_actor_or_destroy_function (tree orig, tree fn_type, + tree coro_frame_ptr, bool actor_p) { - tree fn_name = get_fn_local_identifier (orig, name); location_t loc = DECL_SOURCE_LOCATION (orig); - tree fn = build_lang_decl (FUNCTION_DECL, fn_name, fn_type); + tree fn + = build_lang_decl (FUNCTION_DECL, copy_node (DECL_NAME (orig)), fn_type); + + /* Allow for locating the ramp (original) function from this one. */ + if (!to_ramp) + to_ramp = hash_map::create_ggc (10); + to_ramp->put (fn, orig); + DECL_CONTEXT (fn) = DECL_CONTEXT (orig); DECL_SOURCE_LOCATION (fn) = loc; DECL_ARTIFICIAL (fn) = true; @@ -4021,6 +4071,17 @@ act_des_fn (tree orig, tree fn_type, tree coro_frame_ptr, const char* name) /* This is a coroutine component. */ DECL_COROUTINE_P (fn) = 1; + /* Set up a means to find out if a decl is one of the helpers and, if so, + which one. */ + if (coroutine_info *info = get_coroutine_info (orig)) + { + gcc_checking_assert ((actor_p && info->actor_decl == NULL_TREE) + || info->destroy_decl == NULL_TREE); + if (actor_p) + info->actor_decl = fn; + else + info->destroy_decl = fn; + } return fn; } @@ -4329,8 +4390,10 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) tree act_des_fn_ptr = build_pointer_type (act_des_fn_type); /* Declare the actor and destroyer function. */ - tree actor = act_des_fn (orig, act_des_fn_type, coro_frame_ptr, "actor"); - tree destroy = act_des_fn (orig, act_des_fn_type, coro_frame_ptr, "destroy"); + tree actor = coro_build_actor_or_destroy_function (orig, act_des_fn_type, + coro_frame_ptr, true); + tree destroy = coro_build_actor_or_destroy_function (orig, act_des_fn_type, + coro_frame_ptr, false); /* Construct the wrapped function body; we will analyze this to determine the requirements for the coroutine frame. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f4bcab5..ddf8f43 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5166,6 +5166,21 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define DECL_COROUTINE_P(NODE) \ (LANG_DECL_FN_CHECK (DECL_COMMON_CHECK (NODE))->coroutine_p) +/* For a FUNCTION_DECL of a coroutine, this holds the ACTOR helper function + decl. */ +#define DECL_ACTOR_FN(NODE) \ + (coro_get_actor_function ((NODE))) + +/* For a FUNCTION_DECL of a coroutine, this holds the DESTROY helper function + decl. */ +#define DECL_DESTROY_FN(NODE) \ + (coro_get_destroy_function ((NODE))) + +/* For a FUNCTION_DECL of a coroutine helper (ACTOR or DESTROY), this points + back to the original (ramp) function. */ +#define DECL_RAMP_FN(NODE) \ + (coro_get_ramp_function (NODE)) + /* True for an OMP_ATOMIC that has dependent parameters. These are stored as an expr in operand 1, and integer_zero_node or clauses in operand 0. */ #define OMP_ATOMIC_DEPENDENT_P(NODE) \ @@ -5584,6 +5599,7 @@ extern GTY(()) vec *keyed_classes; #ifndef NO_DOT_IN_LABEL #define JOINER '.' +#define JOIN_STR "." #define AUTO_TEMP_NAME "_.tmp_" #define VFIELD_BASE ".vf" @@ -5595,6 +5611,7 @@ extern GTY(()) vec *keyed_classes; #ifndef NO_DOLLAR_IN_LABEL #define JOINER '$' +#define JOIN_STR "$" #define AUTO_TEMP_NAME "_$tmp_" #define VFIELD_BASE "$vf" @@ -5603,6 +5620,8 @@ extern GTY(()) vec *keyed_classes; #else /* NO_DOLLAR_IN_LABEL */ +#define JOIN_STR "_" + #define VTABLE_NAME "__vt_" #define VTABLE_NAME_P(ID_NODE) \ (!strncmp (IDENTIFIER_POINTER (ID_NODE), VTABLE_NAME, \ @@ -8292,6 +8311,9 @@ extern tree finish_co_yield_expr (location_t, tree); extern tree coro_validate_builtin_call (tree, tsubst_flags_t = tf_warning_or_error); extern bool morph_fn_to_coro (tree, tree *, tree *); +extern tree coro_get_actor_function (tree); +extern tree coro_get_destroy_function (tree); +extern tree coro_get_ramp_function (tree); /* Inline bodies. */ diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index ee14c2d..bf4abba 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -832,6 +832,18 @@ write_encoding (const tree decl) write_bare_function_type (fn_type, mangle_return_type_p (decl), d); + + /* If this is a coroutine helper, then append an appropriate string to + identify which. */ + if (tree ramp = DECL_RAMP_FN (decl)) + { + if (DECL_ACTOR_FN (ramp) == decl) + write_string (JOIN_STR "actor"); + else if (DECL_DESTROY_FN (ramp) == decl) + write_string (JOIN_STR "destroy"); + else + gcc_unreachable (); + } } } @@ -1423,9 +1435,12 @@ write_unqualified_name (tree decl) } else if (DECL_OVERLOADED_OPERATOR_P (decl)) { + tree t; + if (!(t = DECL_RAMP_FN (decl))) + t = decl; const char *mangled_name - = (ovl_op_info[DECL_ASSIGNMENT_OPERATOR_P (decl)] - [DECL_OVERLOADED_OPERATOR_CODE_RAW (decl)].mangled_name); + = (ovl_op_info[DECL_ASSIGNMENT_OPERATOR_P (t)] + [DECL_OVERLOADED_OPERATOR_CODE_RAW (t)].mangled_name); write_string (mangled_name); } else if (UDLIT_OPER_P (DECL_NAME (decl))) -- cgit v1.1 From 21ea2f9320d31d3d925031a8ba189d9b19e52bc1 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 20 Jul 2021 00:16:38 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0c4734f..bb46293 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2021-07-19 Iain Sandoe + + PR c++/95520 + * coroutines.cc (struct coroutine_info): Add fields for + actor and destroy function decls. + (to_ramp): New. + (coro_get_ramp_function): New. + (coro_get_actor_function): New. + (coro_get_destroy_function): New. + (act_des_fn): Set up mapping between ramp, actor and + destroy functions. + (morph_fn_to_coro): Adjust interface to the builder for + helper function decls. + * cp-tree.h (DECL_ACTOR_FN, DECL_DESTROY_FN, DECL_RAMP_FN, + JOIN_STR): New. + * mangle.c (write_encoding): Handle coroutine helpers. + (write_unqualified_name): Handle lambda coroutine helpers. + 2021-07-16 Patrick Palka PR c++/101233 -- 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') 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/parser.c | 11 +++++++++-- gcc/cp/pt.c | 1 + gcc/cp/semantics.c | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 821ce17..45216f0 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -35656,6 +35656,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OACC_CLAUSE_NO_CREATE; else if (!strcmp ("nogroup", p)) result = PRAGMA_OMP_CLAUSE_NOGROUP; + else if (!strcmp ("nohost", p)) + result = PRAGMA_OACC_CLAUSE_NOHOST; else if (!strcmp ("nontemporal", p)) result = PRAGMA_OMP_CLAUSE_NONTEMPORAL; else if (!strcmp ("notinbranch", p)) @@ -38879,6 +38881,11 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); c_name = "no_create"; break; + case PRAGMA_OACC_CLAUSE_NOHOST: + clauses = cp_parser_oacc_simple_clause (here, OMP_CLAUSE_NOHOST, + clauses); + c_name = "nohost"; + break; case PRAGMA_OACC_CLAUSE_NUM_GANGS: code = OMP_CLAUSE_NUM_GANGS; c_name = "num_gangs"; @@ -44866,8 +44873,8 @@ cp_parser_omp_taskloop (cp_parser *parser, cp_token *pragma_tok, ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ)) - + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NOHOST) ) /* Parse the OpenACC routine pragma. This has an optional '( name )' component, which must resolve to a declared namespace-scope diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 94ca3bc..b396ddd 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17479,6 +17479,7 @@ tsubst_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; default: gcc_unreachable (); 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 419c6c68e60adc8801b44dab72ebcd680cfe1d97 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 22 Jul 2021 00:16:46 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bb46293..37ea7f5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2021-07-21 Thomas Schwinge + Joseph Myers + Cesar Philippidis + + * 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. + +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. + 2021-07-19 Iain Sandoe PR c++/95520 -- cgit v1.1 From 2c5d803d03209478b4f060785c6f6ba2f0de88ad Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 23 Jul 2021 09:37:36 +0200 Subject: openmp: Diagnose invalid mixing of the attribute and pragma syntax directives The OpenMP 5.1 spec says that the attribute and pragma syntax directives should not be mixed on the same statement. The following patch adds diagnostic for that, [[omp::directive (...)]] #pragma omp ... is always an error and for the other order #pragma omp ... [[omp::directive (...)]] it depends on whether the pragma directive is an OpenMP construct (then it is an error because it needs a structured block or loop or statement as body) or e.g. a standalone directive (then it is fine). Only block scope is handled for now though, namespace scope and class scope still needs implementing even the basic support. 2021-07-23 Jakub Jelinek gcc/c-family/ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP__START_ and PRAGMA_OMP__LAST_ enumerators. gcc/cp/ * parser.h (struct cp_parser): Add omp_attrs_forbidden_p member. * parser.c (cp_parser_handle_statement_omp_attributes): Diagnose mixing of attribute and pragma syntax directives when seeing omp::directive if parser->omp_attrs_forbidden_p or if attribute syntax directives are followed by OpenMP pragma. (cp_parser_statement): Clear parser->omp_attrs_forbidden_p after the cp_parser_handle_statement_omp_attributes call. (cp_parser_omp_structured_block): Add disallow_omp_attrs argument, if true, set parser->omp_attrs_forbidden_p. (cp_parser_omp_scan_loop_body, cp_parser_omp_sections_scope): Pass false as disallow_omp_attrs to cp_parser_omp_structured_block. (cp_parser_omp_parallel, cp_parser_omp_task): Set parser->omp_attrs_forbidden_p. gcc/testsuite/ * g++.dg/gomp/attrs-4.C: New test. * g++.dg/gomp/attrs-5.C: New test. --- gcc/cp/parser.c | 40 +++++++++++++++++++++++++++++++++++----- gcc/cp/parser.h | 3 +++ 2 files changed, 38 insertions(+), 5 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 45216f0..18905cf 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11665,6 +11665,7 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) auto_vec vec; int cnt = 0; int tokens = 0; + bool bad = false; for (tree *pa = &attrs; *pa; ) if (get_attribute_namespace (*pa) == omp_identifier && is_attribute_p ("directive", get_attribute_name (*pa))) @@ -11676,6 +11677,14 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); cp_token *first = DEFPARSE_TOKENS (d)->first; cp_token *last = DEFPARSE_TOKENS (d)->last; + if (parser->omp_attrs_forbidden_p) + { + error_at (first->location, + "mixing OpenMP directives with attribute and pragma " + "syntax on the same statement"); + parser->omp_attrs_forbidden_p = false; + bad = true; + } const char *directive[3] = {}; for (int i = 0; i < 3; i++) { @@ -11731,6 +11740,9 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) else pa = &TREE_CHAIN (*pa); + if (bad) + return attrs; + unsigned int i; cp_omp_attribute_data *v; cp_omp_attribute_data *construct_seen = nullptr; @@ -11780,6 +11792,18 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) " can only appear on an empty statement"); return attrs; } + if (cnt && cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)) + { + cp_token *token = cp_lexer_peek_token (parser->lexer); + enum pragma_kind kind = cp_parser_pragma_kind (token); + if (kind >= PRAGMA_OMP__START_ && kind <= PRAGMA_OMP__LAST_) + { + error_at (token->location, + "mixing OpenMP directives with attribute and pragma " + "syntax on the same statement"); + return attrs; + } + } if (!tokens) return attrs; @@ -11904,6 +11928,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, if (std_attrs && (flag_openmp || flag_openmp_simd)) std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs); + parser->omp_attrs_forbidden_p = false; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -39391,11 +39416,14 @@ cp_parser_end_omp_structured_block (cp_parser *parser, unsigned save) } static tree -cp_parser_omp_structured_block (cp_parser *parser, bool *if_p) +cp_parser_omp_structured_block (cp_parser *parser, bool *if_p, + bool disallow_omp_attrs = true) { tree stmt = begin_omp_structured_block (); unsigned int save = cp_parser_begin_omp_structured_block (parser); + if (disallow_omp_attrs) + parser->omp_attrs_forbidden_p = true; cp_parser_statement (parser, NULL_TREE, false, if_p); cp_parser_end_omp_structured_block (parser, save); @@ -40761,7 +40789,7 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) if (!braces.require_open (parser)) return; - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build2 (OMP_SCAN, void_type_node, substmt, NULL_TREE); add_stmt (substmt); @@ -40796,7 +40824,7 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) error ("expected %<#pragma omp scan%>"); clauses = finish_omp_clauses (clauses, C_ORT_OMP); - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build2_loc (tok->location, OMP_SCAN, void_type_node, substmt, clauses); add_stmt (substmt); @@ -41597,7 +41625,7 @@ cp_parser_omp_sections_scope (cp_parser *parser) if (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer)) != PRAGMA_OMP_SECTION) { - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build1 (OMP_SECTION, void_type_node, substmt); add_stmt (substmt); } @@ -41622,7 +41650,7 @@ cp_parser_omp_sections_scope (cp_parser *parser) error_suppress = true; } - substmt = cp_parser_omp_structured_block (parser, NULL); + substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build1 (OMP_SECTION, void_type_node, substmt); add_stmt (substmt); } @@ -41842,6 +41870,7 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, block = begin_omp_parallel (); save = cp_parser_begin_omp_structured_block (parser); + parser->omp_attrs_forbidden_p = true; cp_parser_statement (parser, NULL_TREE, false, if_p); cp_parser_end_omp_structured_block (parser, save); stmt = finish_omp_parallel (clauses, block); @@ -41904,6 +41933,7 @@ cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok, bool *if_p) "#pragma omp task", pragma_tok); block = begin_omp_task (); save = cp_parser_begin_omp_structured_block (parser); + parser->omp_attrs_forbidden_p = true; cp_parser_statement (parser, NULL_TREE, false, if_p); cp_parser_end_omp_structured_block (parser, save); return finish_omp_task (clauses, block); diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 5ef7047..6fdd214 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -398,6 +398,9 @@ struct GTY(()) cp_parser { identifiers) rather than an explicit template parameter list. */ bool fully_implicit_function_template_p; + /* TRUE if omp::directive or omp::sequence attributes may not appear. */ + bool omp_attrs_forbidden_p; + /* Tracks the function's template parameter list when declaring a function using generic type parameters. This is either a new chain in the case of a fully implicit function template or an extension of the function's existing -- cgit v1.1 From ead235f60139edc6eb408d8d083cbb15e417b447 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 24 Jul 2021 00:16:44 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 37ea7f5..293f620 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2021-07-23 Jakub Jelinek + + * parser.h (struct cp_parser): Add omp_attrs_forbidden_p member. + * parser.c (cp_parser_handle_statement_omp_attributes): Diagnose + mixing of attribute and pragma syntax directives when seeing + omp::directive if parser->omp_attrs_forbidden_p or if attribute syntax + directives are followed by OpenMP pragma. + (cp_parser_statement): Clear parser->omp_attrs_forbidden_p after + the cp_parser_handle_statement_omp_attributes call. + (cp_parser_omp_structured_block): Add disallow_omp_attrs argument, + if true, set parser->omp_attrs_forbidden_p. + (cp_parser_omp_scan_loop_body, cp_parser_omp_sections_scope): Pass + false as disallow_omp_attrs to cp_parser_omp_structured_block. + (cp_parser_omp_parallel, cp_parser_omp_task): Set + parser->omp_attrs_forbidden_p. + 2021-07-21 Thomas Schwinge Joseph Myers Cesar Philippidis -- cgit v1.1 From acf9d1fd806fabf62dfe232439b11263c191e32d Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 26 Jul 2021 09:13:47 +0200 Subject: openmp: Add support for omp attributes section and scan directives This patch adds support for expressing the section and scan directives using the attribute syntax and additionally fixes some bugs in the attribute syntax directive handling. For now it requires that the scan and section directives appear as the only attribute, not combined with other OpenMP or non-OpenMP attributes on the same statement. 2021-07-26 Jakub Jelinek * parser.h (struct cp_lexer): Add orphan_p member. * parser.c (cp_parser_statement): Don't change in_omp_attribute_pragma upon restart from CPP_PRAGMA handling. Fix up condition when a lexer should be destroyed and adjust saved_tokens if it records tokens from the to be destroyed lexer. (cp_parser_omp_section_scan): New function. (cp_parser_omp_scan_loop_body): Use it. If parser->lexer->in_omp_attribute_pragma, allow optional comma after scan. (cp_parser_omp_sections_scope): Use cp_parser_omp_section_scan. * g++.dg/gomp/attrs-1.C: Use attribute syntax even for section and scan directives. * g++.dg/gomp/attrs-2.C: Likewise. * g++.dg/gomp/attrs-6.C: New test. * g++.dg/gomp/attrs-7.C: New test. * g++.dg/gomp/attrs-8.C: New test. --- gcc/cp/parser.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- gcc/cp/parser.h | 4 +++ 2 files changed, 104 insertions(+), 5 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 18905cf..976e2e7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11901,10 +11901,9 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, tree statement, std_attrs = NULL_TREE; cp_token *token; location_t statement_location, attrs_loc; - bool in_omp_attribute_pragma; + bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; restart: - in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; if (if_p != NULL) *if_p = false; /* There is no statement yet. */ @@ -11951,6 +11950,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, the statement. */ cp_parser_label_for_labeled_statement (parser, std_attrs); in_compound = false; + in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; goto restart; case RID_IF: @@ -12034,6 +12034,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, cp_parser_label_for_labeled_statement (parser, std_attrs); in_compound = false; + in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; goto restart; } } @@ -12058,13 +12059,28 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, cp_parser_pragma (parser, pragma_compound, if_p); else if (!cp_parser_pragma (parser, pragma_stmt, if_p)) do_restart = true; - if (lexer->in_omp_attribute_pragma && !in_omp_attribute_pragma) + if (parser->lexer != lexer + && lexer->in_omp_attribute_pragma + && (!in_omp_attribute_pragma || lexer->orphan_p)) { - gcc_assert (parser->lexer != lexer); + if (saved_tokens.lexer == lexer) + { + if (saved_tokens.commit) + cp_lexer_commit_tokens (lexer); + gcc_assert (lexer->saved_tokens.length () == saved_tokens.len); + saved_tokens.lexer = parser->lexer; + saved_tokens.commit = false; + saved_tokens.len = parser->lexer->saved_tokens.length (); + } cp_lexer_destroy (lexer); + lexer = parser->lexer; } if (do_restart) goto restart; + if (parser->lexer == lexer + && lexer->in_omp_attribute_pragma + && !in_omp_attribute_pragma) + parser->lexer->orphan_p = true; return; } else if (token->type == CPP_EOF) @@ -40775,6 +40791,77 @@ cp_finish_omp_range_for (tree orig, tree begin) cp_finish_decomp (decl, decomp_first_name, decomp_cnt); } +/* Return true if next tokens contain a standard attribute that contains + omp::directive (DIRECTIVE). */ + +static bool +cp_parser_omp_section_scan (cp_parser *parser, const char *directive, + bool tentative) +{ + size_t n = cp_parser_skip_attributes_opt (parser, 1), i; + if (n < 10) + return false; + for (i = 5; i < n - 4; i++) + if (cp_lexer_nth_token_is (parser->lexer, i, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, i + 1, CPP_OPEN_PAREN) + && cp_lexer_nth_token_is (parser->lexer, i + 2, CPP_NAME)) + { + tree first = cp_lexer_peek_nth_token (parser->lexer, i)->u.value; + tree second = cp_lexer_peek_nth_token (parser->lexer, i + 2)->u.value; + if (strcmp (IDENTIFIER_POINTER (first), "directive")) + continue; + if (strcmp (IDENTIFIER_POINTER (second), directive) == 0) + break; + } + if (i == n - 4) + return false; + cp_parser_parse_tentatively (parser); + location_t first_loc = cp_lexer_peek_token (parser->lexer)->location; + location_t last_loc + = cp_lexer_peek_nth_token (parser->lexer, n - 1)->location; + location_t middle_loc = UNKNOWN_LOCATION; + tree std_attrs = cp_parser_std_attribute_spec_seq (parser); + int cnt = 0; + bool seen = false; + for (tree attr = std_attrs; attr; attr = TREE_CHAIN (attr)) + if (get_attribute_namespace (attr) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (attr))) + { + for (tree a = TREE_VALUE (attr); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cnt++; + if (first->type == CPP_NAME + && strcmp (IDENTIFIER_POINTER (first->u.value), + directive) == 0) + { + seen = true; + if (middle_loc == UNKNOWN_LOCATION) + middle_loc = first->location; + } + } + } + if (!seen || tentative) + { + cp_parser_abort_tentative_parse (parser); + return seen; + } + if (cnt != 1 || TREE_CHAIN (std_attrs)) + { + error_at (make_location (first_loc, last_loc, middle_loc), + "%<[[omp::directive(%s)]]%> must be the only specified " + "attribute on a statement", directive); + cp_parser_abort_tentative_parse (parser); + return false; + } + if (!cp_parser_parse_definitely (parser)) + return false; + cp_parser_handle_statement_omp_attributes (parser, std_attrs); + return true; +} + /* OpenMP 5.0: scan-loop-body: @@ -40793,6 +40880,7 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) substmt = build2 (OMP_SCAN, void_type_node, substmt, NULL_TREE); add_stmt (substmt); + cp_parser_omp_section_scan (parser, "scan", false); cp_token *tok = cp_lexer_peek_token (parser->lexer); if (cp_parser_pragma_kind (tok) == PRAGMA_OMP_SCAN) { @@ -40800,6 +40888,10 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) cp_lexer_consume_token (parser->lexer); + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -41623,7 +41715,8 @@ cp_parser_omp_sections_scope (cp_parser *parser) stmt = push_stmt_list (); if (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer)) - != PRAGMA_OMP_SECTION) + != PRAGMA_OMP_SECTION + && !cp_parser_omp_section_scan (parser, "section", true)) { substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build1 (OMP_SECTION, void_type_node, substmt); @@ -41638,6 +41731,8 @@ cp_parser_omp_sections_scope (cp_parser *parser) if (tok->type == CPP_EOF) break; + if (cp_parser_omp_section_scan (parser, "section", false)) + tok = cp_lexer_peek_token (parser->lexer); if (cp_parser_pragma_kind (tok) == PRAGMA_OMP_SECTION) { cp_lexer_consume_token (parser->lexer); diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 6fdd214..e62742d 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -117,6 +117,10 @@ struct GTY (()) cp_lexer { /* True if we're in the context of OpenMP directives written as C++11 attributes turned into pragma. */ bool in_omp_attribute_pragma; + + /* True for in_omp_attribute_pragma lexer that should be destroyed + when it is no longer in use. */ + bool orphan_p; }; -- cgit v1.1 From 1a7febe9432f5302620aebc9cb5760c6c1d31d4c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 27 Jul 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 293f620..6f8c4f0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2021-07-26 Jakub Jelinek + + * parser.h (struct cp_lexer): Add orphan_p member. + * parser.c (cp_parser_statement): Don't change in_omp_attribute_pragma + upon restart from CPP_PRAGMA handling. Fix up condition when a lexer + should be destroyed and adjust saved_tokens if it records tokens from + the to be destroyed lexer. + (cp_parser_omp_section_scan): New function. + (cp_parser_omp_scan_loop_body): Use it. If + parser->lexer->in_omp_attribute_pragma, allow optional comma + after scan. + (cp_parser_omp_sections_scope): Use cp_parser_omp_section_scan. + 2021-07-23 Jakub Jelinek * parser.h (struct cp_parser): Add omp_attrs_forbidden_p member. -- cgit v1.1 From bee2f80b901d73f50275f2b44932067ffcf616ca Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 16 Jul 2021 15:58:01 -0400 Subject: c++: Reject ordered comparison of null pointers [PR99701] When implementing DR 1512 in r11-467 I neglected to reject ordered comparison of two null pointers, like nullptr < nullptr. This patch fixes that omission. DR 1512 PR c++/99701 gcc/cp/ChangeLog: * cp-gimplify.c (cp_fold): Remove {LE,LT,GE,GT_EXPR} from a switch. * typeck.c (cp_build_binary_op): Reject ordered comparison of two null pointers. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/nullptr11.C: Remove invalid tests. * g++.dg/cpp0x/nullptr46.C: Add dg-error. * g++.dg/cpp2a/spaceship-err7.C: New test. * g++.dg/expr/ptr-comp4.C: New test. libstdc++-v3/ChangeLog: * testsuite/20_util/tuple/comparison_operators/overloaded.cc: Move a line... * testsuite/20_util/tuple/comparison_operators/overloaded2.cc: ...here. New test. --- gcc/cp/cp-gimplify.c | 4 ---- gcc/cp/typeck.c | 15 +++------------ 2 files changed, 3 insertions(+), 16 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index ff0bff7..0520fa4 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -2433,13 +2433,9 @@ cp_fold (tree x) switch (code) { case EQ_EXPR: - case LE_EXPR: - case GE_EXPR: x = constant_boolean_node (true, TREE_TYPE (x)); break; case NE_EXPR: - case LT_EXPR: - case GT_EXPR: x = constant_boolean_node (false, TREE_TYPE (x)); break; default: diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index a483e1f..738e69a 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5483,7 +5483,9 @@ cp_build_binary_op (const op_location_t &location, result_type = composite_pointer_type (location, type0, type1, op0, op1, CPO_COMPARISON, complain); - else if (code0 == POINTER_TYPE && null_ptr_cst_p (orig_op1)) + else if ((code0 == POINTER_TYPE && null_ptr_cst_p (orig_op1)) + || (code1 == POINTER_TYPE && null_ptr_cst_p (orig_op0)) + || (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1))) { /* Core Issue 1512 made this ill-formed. */ if (complain & tf_error) @@ -5491,17 +5493,6 @@ cp_build_binary_op (const op_location_t &location, "integer zero (%qT and %qT)", type0, type1); return error_mark_node; } - else if (code1 == POINTER_TYPE && null_ptr_cst_p (orig_op0)) - { - /* Core Issue 1512 made this ill-formed. */ - if (complain & tf_error) - error_at (location, "ordered comparison of pointer with " - "integer zero (%qT and %qT)", type0, type1); - return error_mark_node; - } - else if (null_ptr_cst_p (orig_op0) && null_ptr_cst_p (orig_op1)) - /* One of the operands must be of nullptr_t type. */ - result_type = TREE_TYPE (nullptr_node); else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) { result_type = type0; -- cgit v1.1 From af3f12e6e869adcbb1cec09cedba627d4bbf69a4 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 28 Jul 2021 00:16:25 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6f8c4f0..217a1ac 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2021-07-27 Marek Polacek + + DR 1512 + PR c++/99701 + * cp-gimplify.c (cp_fold): Remove {LE,LT,GE,GT_EXPR} from + a switch. + * typeck.c (cp_build_binary_op): Reject ordered comparison + of two null pointers. + 2021-07-26 Jakub Jelinek * parser.h (struct cp_lexer): Add orphan_p member. -- cgit v1.1 From 2a837de28ee94b4ec201059a9a7aaa852e6808da Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Wed, 28 Jul 2021 15:28:10 -0600 Subject: Add new gimple-ssa-warn-access pass. gcc/ChangeLog: * Makefile.in (OBJS): Add gimple-ssa-warn-access.o and pointer-query.o. * attribs.h (fndecl_dealloc_argno): Move fndecl_dealloc_argno to tree.h. * builtins.c (compute_objsize_r): Move to pointer-query.cc. (access_ref::access_ref): Same. (access_ref::phi): Same. (access_ref::get_ref): Same. (access_ref::size_remaining): Same. (access_ref::offset_in_range): Same. (access_ref::add_offset): Same. (access_ref::inform_access): Same. (ssa_name_limit_t::visit_phi): Same. (ssa_name_limit_t::leave_phi): Same. (ssa_name_limit_t::next): Same. (ssa_name_limit_t::next_phi): Same. (ssa_name_limit_t::~ssa_name_limit_t): Same. (pointer_query::pointer_query): Same. (pointer_query::get_ref): Same. (pointer_query::put_ref): Same. (pointer_query::flush_cache): Same. (warn_string_no_nul): Move to gimple-ssa-warn-access.cc. (check_nul_terminated_array): Same. (unterminated_array): Same. (maybe_warn_for_bound): Same. (check_read_access): Same. (warn_for_access): Same. (get_size_range): Same. (check_access): Same. (gimple_call_alloc_size): Move to tree.c. (gimple_parm_array_size): Move to pointer-query.cc. (get_offset_range): Same. (gimple_call_return_array): Same. (handle_min_max_size): Same. (handle_array_ref): Same. (handle_mem_ref): Same. (compute_objsize): Same. (gimple_call_alloc_p): Move to gimple-ssa-warn-access.cc. (call_dealloc_argno): Same. (fndecl_dealloc_argno): Same. (new_delete_mismatch_p): Same. (matching_alloc_calls_p): Same. (warn_dealloc_offset): Same. (maybe_emit_free_warning): Same. * builtins.h (check_nul_terminated_array): Move to gimple-ssa-warn-access.h. (check_nul_terminated_array): Same. (warn_string_no_nul): Same. (unterminated_array): Same. (class ssa_name_limit_t): Same. (class pointer_query): Same. (struct access_ref): Same. (class range_query): Same. (struct access_data): Same. (gimple_call_alloc_size): Same. (gimple_parm_array_size): Same. (compute_objsize): Same. (class access_data): Same. (maybe_emit_free_warning): Same. * calls.c (initialize_argument_information): Remove call to maybe_emit_free_warning. * gimple-array-bounds.cc: Include new header.. * gimple-fold.c: Same. * gimple-ssa-sprintf.c: Same. * gimple-ssa-warn-restrict.c: Same. * passes.def: Add pass_warn_access. * tree-pass.h (make_pass_warn_access): Declare. * tree-ssa-strlen.c: Include new headers. * tree.c (fndecl_dealloc_argno): Move here from builtins.c. * tree.h (fndecl_dealloc_argno): Move here from attribs.h. * gimple-ssa-warn-access.cc: New file. * gimple-ssa-warn-access.h: New file. * pointer-query.cc: New file. * pointer-query.h: New file. gcc/cp/ChangeLog: * init.c: Include new header. --- gcc/cp/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index d47e405..229c84e 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -34,7 +34,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "asan.h" #include "stor-layout.h" -#include "builtins.h" +#include "pointer-query.h" static bool begin_init_stmts (tree *, tree *); static tree finish_init_stmts (bool, tree, tree); -- cgit v1.1 From 3916902930769d5172c0feaa5f535ca7b2bafdf7 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 29 Jul 2021 00:16:43 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 217a1ac..27323bb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,7 @@ +2021-07-28 Martin Sebor + + * init.c: Include new header. + 2021-07-27 Marek Polacek DR 1512 -- cgit v1.1 From 77ab4e3be2d92b1ff671d58418d852195f10dd20 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 30 Jul 2021 10:30:16 +0200 Subject: c++: Accept C++11 attribute-definition [PR101582] As the following testcase shows, we don't parse properly C++11 attribute-declaration: https://eel.is/c++draft/dcl.dcl#nt:attribute-declaration cp_parser_toplevel_declaration just handles empty-declaration parsing (with diagnostics for C++98) and otherwise calls cp_parser_declaration which on it calls cp_parser_simple_declaration and rejects it with "does not declare anything" permerror. The following patch moves the handling of empty-declaration from cp_parser_toplevel_declaration to cp_parser_declaration and handles attribute-declaration in cp_parser_declaration by parsing the attributes (standard ones only, we've never supported __attribute__((...)); at namespace scope, so I'm not sure we need to introduce that), which for C++98 emits the needed diagnostics, and then warning if there are any attributes that we throw away on the floor. I'll need this later for OpenMP directives at namespace scope, e.g. [[omp::directive (requires, atomic_default_mem_order(seq_cst))]]; should be valid at namespace scope (and many other directives). 2021-07-30 Jakub Jelinek PR c++/101582 * parser.c (cp_parser_skip_std_attribute_spec_seq): Add a forward declaration. (cp_parser_declaration): Parse empty-declaration and attribute-declaration. (cp_parser_toplevel_declaration): Don't parse empty-declaration here. * g++.dg/cpp0x/gen-attrs-45.C: Expect a warning about ignored attributes instead of error. * g++.dg/cpp0x/gen-attrs-75.C: New test. * g++.dg/modules/pr101582-1.C: New test. --- gcc/cp/parser.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 976e2e7..d960d38 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2507,6 +2507,8 @@ static tree cp_parser_std_attribute_spec (cp_parser *); static tree cp_parser_std_attribute_spec_seq (cp_parser *); +static size_t cp_parser_skip_std_attribute_spec_seq + (cp_parser *, size_t); static size_t cp_parser_skip_attributes_opt (cp_parser *, size_t); static bool cp_parser_extension_opt @@ -14405,6 +14407,30 @@ cp_parser_declaration (cp_parser* parser, tree prefix_attrs) cp_token *token2 = (token1->type == CPP_EOF ? token1 : cp_lexer_peek_nth_token (parser->lexer, 2)); + if (token1->type == CPP_SEMICOLON) + { + cp_lexer_consume_token (parser->lexer); + /* A declaration consisting of a single semicolon is invalid + * before C++11. Allow it unless we're being pedantic. */ + if (cxx_dialect < cxx11) + pedwarn (input_location, OPT_Wpedantic, "extra %<;%>"); + return; + } + else if (cp_lexer_nth_token_is (parser->lexer, + cp_parser_skip_std_attribute_spec_seq (parser, + 1), + CPP_SEMICOLON)) + { + location_t attrs_loc = token1->location; + tree std_attrs = cp_parser_std_attribute_spec_seq (parser); + if (std_attrs != NULL_TREE) + warning_at (make_location (attrs_loc, attrs_loc, parser->lexer), + OPT_Wattributes, "attribute ignored"); + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + cp_lexer_consume_token (parser->lexer); + return; + } + /* Get the high-water mark for the DECLARATOR_OBSTACK. */ void *p = obstack_alloc (&declarator_obstack, 0); @@ -14555,14 +14581,6 @@ cp_parser_toplevel_declaration (cp_parser* parser) cp_parser_declaration. (A #pragma at block scope is handled in cp_parser_statement.) */ cp_parser_pragma (parser, pragma_external, NULL); - else if (token->type == CPP_SEMICOLON) - { - cp_lexer_consume_token (parser->lexer); - /* A declaration consisting of a single semicolon is invalid - * before C++11. Allow it unless we're being pedantic. */ - if (cxx_dialect < cxx11) - pedwarn (input_location, OPT_Wpedantic, "extra %<;%>"); - } else /* Parse the declaration itself. */ cp_parser_declaration (parser, NULL_TREE); -- cgit v1.1 From 0ba2003cf306aa98b6ec91c9d849ab9bafcf17c2 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 30 Jul 2021 17:44:38 +0200 Subject: c++: Fix up attribute rollbacks in cp_parser_statement During the OpenMP directives using C++ attribute syntax work, I've noticed that cp_parser_statement when parsing various block declarations that do not allow attribute-specifier-seq at the start rolls back the attributes only if std_attrs is non-NULL (i.e. some attributes have been parsed), but doesn't roll back if some tokens were parsed as attribute-specifier-seq, but didn't yield any attributes (e.g. [[]][[]][[]][[]]), which means we accept those empty attributes even in places where they don't appear in the grammar. The following patch fixes that by instead checking if there are any tokens to roll back. This makes the parsing handle the first function the same as the second one (where some attribute appears). The testcase contains two xfails, using namespace ... apparently allows attributes at the start and the attributes shall appeartain to using in that case. To be fixed incrementally. 2021-07-30 Jakub Jelinek * parser.c (cp_parser_statement): Rollback attributes not just when std_attrs is non-NULL, but whenever cp_parser_std_attribute_spec_seq parsed any tokens. * g++.dg/cpp0x/gen-attrs-76.C: New test. --- gcc/cp/parser.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d960d38..97078f9 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11904,6 +11904,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, cp_token *token; location_t statement_location, attrs_loc; bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; + bool has_std_attrs; restart: if (if_p != NULL) @@ -11912,7 +11913,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, statement = NULL_TREE; saved_token_sentinel saved_tokens (parser->lexer); - attrs_loc = cp_lexer_peek_token (parser->lexer)->location; + token = cp_lexer_peek_token (parser->lexer); + attrs_loc = token->location; if (c_dialect_objc ()) /* In obj-c++, seeing '[[' might be the either the beginning of c++11 attributes, or a nested objc-message-expression. So @@ -11926,6 +11928,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, if (!cp_parser_parse_definitely (parser)) std_attrs = NULL_TREE; } + has_std_attrs = cp_lexer_peek_token (parser->lexer) != token; if (std_attrs && (flag_openmp || flag_openmp_simd)) std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs); @@ -11994,7 +11997,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, case RID_NAMESPACE: /* This must be a namespace alias definition. */ - if (std_attrs != NULL_TREE) + if (has_std_attrs) { /* Attributes should be parsed as part of the declaration, so let's un-parse them. */ @@ -12099,7 +12102,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, { if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) { - if (std_attrs != NULL_TREE) + if (has_std_attrs) /* Attributes should be parsed as part of the declaration, so let's un-parse them. */ saved_tokens.rollback(); @@ -12111,7 +12114,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, if (cp_parser_parse_definitely (parser)) return; /* It didn't work, restore the post-attribute position. */ - if (std_attrs) + if (has_std_attrs) cp_lexer_set_token_position (parser->lexer, statement_token); } /* All preceding labels have been parsed at this point. */ -- cgit v1.1 From 3ead06c1cff8fb42b4e278c3624917e6b5477f12 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 30 Jul 2021 08:45:01 -0400 Subject: c++: Reject anonymous struct with bases In discussion of jakub's patch for C++20 pointer-interconvertibility, it came up that we allow anonymous structs to have bases, but don't do anything usable with them. Let's reject it. The comment change is something I noticed while looking for the right place to diagnose this: finish_struct_anon does not actually check for anything invalid, so it shouldn't claim to. gcc/cp/ChangeLog: * class.c (finish_struct_anon): Improve comment. * decl.c (fixup_anonymous_aggr): Reject anonymous struct with bases. gcc/testsuite/ChangeLog: * g++.dg/ext/anon-struct8.C: New test. --- gcc/cp/class.c | 3 +-- gcc/cp/decl.c | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 14db066..6f31700 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3072,8 +3072,7 @@ finish_struct_anon_r (tree field) } } -/* Check for things that are invalid. There are probably plenty of other - things we should check for also. */ +/* Fix up any anonymous union/struct members of T. */ static void finish_struct_anon (tree t) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 01d64a1..71308a0 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5084,6 +5084,9 @@ fixup_anonymous_aggr (tree t) { tree field, type; + if (BINFO_N_BASE_BINFOS (TYPE_BINFO (t))) + error_at (location_of (t), "anonymous struct with base classes"); + for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL) { -- 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/constexpr.c | 16 ++++++- gcc/cp/constraint.cc | 4 ++ gcc/cp/cp-gimplify.c | 50 ++++++++++++++------ gcc/cp/cp-objcp-common.c | 1 + gcc/cp/cp-tree.h | 3 ++ gcc/cp/cxx-pretty-print.c | 7 ++- gcc/cp/decl.c | 9 ++++ gcc/cp/parser.c | 5 ++ gcc/cp/semantics.c | 114 ++++++++++++++++++++++++++++++++++++++++++++-- gcc/cp/tree.c | 15 ++++-- 10 files changed, 200 insertions(+), 24 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 31fa5b6..1af365d 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1427,8 +1427,20 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, && ctx->call && ctx->call->fundef) current_function_decl = ctx->call->fundef->decl; - new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), - CALL_EXPR_FN (t), nargs, args); + if (fndecl_built_in_p (fun, + CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, + BUILT_IN_FRONTEND)) + { + location_t loc = EXPR_LOCATION (t); + if (nargs >= 1) + VERIFY_CONSTANT (args[0]); + new_call + = fold_builtin_is_pointer_inverconvertible_with_class (loc, nargs, + args); + } + else + new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), + CALL_EXPR_FN (t), nargs, args); current_function_decl = save_cur_fn; force_folding_builtin_constant_p = save_ffbcp; if (new_call == NULL) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 4ee5215..e608c5a 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3631,6 +3631,10 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_IS_LITERAL_TYPE: inform (loc, " %qT is not a literal type", t1); break; + case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF: + inform (loc, " %qT is not pointer-interconvertible base of %qT", + t1, t2); + break; case CPTK_IS_POD: inform (loc, " %qT is not a POD type", t1); break; diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 0520fa4..6e274ac 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -648,14 +648,23 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) if (ret != GS_ERROR) { tree decl = cp_get_callee_fndecl_nofold (*expr_p); - if (decl - && fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED, - BUILT_IN_FRONTEND)) - *expr_p = boolean_false_node; - else if (decl - && fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION, - BUILT_IN_FRONTEND)) - *expr_p = fold_builtin_source_location (EXPR_LOCATION (*expr_p)); + if (decl && fndecl_built_in_p (decl, BUILT_IN_FRONTEND)) + switch (DECL_FE_FUNCTION_CODE (decl)) + { + case CP_BUILT_IN_IS_CONSTANT_EVALUATED: + *expr_p = boolean_false_node; + break; + case CP_BUILT_IN_SOURCE_LOCATION: + *expr_p + = fold_builtin_source_location (EXPR_LOCATION (*expr_p)); + break; + case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: + *expr_p + = fold_builtin_is_pointer_inverconvertible_with_class + (EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p), + &CALL_EXPR_ARG (*expr_p, 0)); + break; + } } break; @@ -2560,11 +2569,26 @@ cp_fold (tree x) && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) nw = 1; - /* Defer folding __builtin_is_constant_evaluated. */ - if (callee - && fndecl_built_in_p (callee, CP_BUILT_IN_IS_CONSTANT_EVALUATED, - BUILT_IN_FRONTEND)) - break; + if (callee && fndecl_built_in_p (callee, BUILT_IN_FRONTEND)) + { + switch (DECL_FE_FUNCTION_CODE (callee)) + { + /* Defer folding __builtin_is_constant_evaluated. */ + case CP_BUILT_IN_IS_CONSTANT_EVALUATED: + break; + case CP_BUILT_IN_SOURCE_LOCATION: + x = fold_builtin_source_location (EXPR_LOCATION (x)); + break; + case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: + x = fold_builtin_is_pointer_inverconvertible_with_class + (EXPR_LOCATION (x), call_expr_nargs (x), + &CALL_EXPR_ARG (x, 0)); + break; + default: + break; + } + break; + } if (callee && fndecl_built_in_p (callee, CP_BUILT_IN_SOURCE_LOCATION, diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index ee25573..beef012 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -414,6 +414,7 @@ names_builtin_p (const char *name) case RID_IS_ENUM: case RID_IS_FINAL: case RID_IS_LITERAL_TYPE: + case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: case RID_IS_POD: case RID_IS_POLYMORPHIC: case RID_IS_SAME_AS: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ddf8f43..9a47a87 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1366,6 +1366,7 @@ enum cp_trait_kind CPTK_IS_ENUM, CPTK_IS_FINAL, CPTK_IS_LITERAL_TYPE, + CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, CPTK_IS_POD, CPTK_IS_POLYMORPHIC, CPTK_IS_SAME_AS, @@ -6355,6 +6356,7 @@ struct GTY((chain_next ("%h.next"))) tinst_level { enum cp_built_in_function { CP_BUILT_IN_IS_CONSTANT_EVALUATED, CP_BUILT_IN_INTEGER_PACK, + CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, CP_BUILT_IN_SOURCE_LOCATION, CP_BUILT_IN_LAST }; @@ -7570,6 +7572,7 @@ extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, bool, bool); extern tree finish_decltype_type (tree, bool, tsubst_flags_t); +extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *); extern tree finish_trait_expr (location_t, enum cp_trait_kind, tree, tree); extern tree build_lambda_expr (void); extern tree build_lambda_object (tree); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 3709d0f..b899162 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2645,6 +2645,9 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) case CPTK_IS_FINAL: pp_cxx_ws_string (pp, "__is_final"); break; + case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF: + pp_cxx_ws_string (pp, "__is_pointer_interconvertible_base_of"); + break; case CPTK_IS_POD: pp_cxx_ws_string (pp, "__is_pod"); break; @@ -2695,7 +2698,9 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) pp_cxx_left_paren (pp); pp->type_id (TRAIT_EXPR_TYPE1 (t)); - if (kind == CPTK_IS_BASE_OF || kind == CPTK_IS_SAME_AS) + if (kind == CPTK_IS_BASE_OF + || kind == CPTK_IS_SAME_AS + || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF) { pp_cxx_separate_with (pp, ','); pp->type_id (TRAIT_EXPR_TYPE2 (t)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 71308a0..e4be6be 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4467,6 +4467,15 @@ cxx_init_decl_processing (void) BUILT_IN_FRONTEND, NULL, NULL_TREE); set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF); + tree bool_vaftype = build_varargs_function_type_list (boolean_type_node, + NULL_TREE); + decl + = add_builtin_function ("__builtin_is_pointer_interconvertible_with_class", + bool_vaftype, + CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, + BUILT_IN_FRONTEND, NULL, NULL_TREE); + set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF); + integer_two_node = build_int_cst (NULL_TREE, 2); /* Guess at the initial static decls size. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 97078f9..ab74e9d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -5799,6 +5799,7 @@ cp_parser_primary_expression (cp_parser *parser, case RID_IS_ENUM: case RID_IS_FINAL: case RID_IS_LITERAL_TYPE: + case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: case RID_IS_POD: case RID_IS_POLYMORPHIC: case RID_IS_SAME_AS: @@ -10688,6 +10689,10 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) case RID_IS_LITERAL_TYPE: kind = CPTK_IS_LITERAL_TYPE; break; + case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: + kind = CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF; + binary = true; + break; case RID_IS_POD: kind = CPTK_IS_POD; break; 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, diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 2a14fa9..8345396 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -450,11 +450,16 @@ builtin_valid_in_constant_expr_p (const_tree decl) return false; if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL) { - if (fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED, - BUILT_IN_FRONTEND) - || fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION, - BUILT_IN_FRONTEND)) - return true; + if (fndecl_built_in_p (decl, BUILT_IN_FRONTEND)) + switch (DECL_FE_FUNCTION_CODE (decl)) + { + case CP_BUILT_IN_IS_CONSTANT_EVALUATED: + case CP_BUILT_IN_SOURCE_LOCATION: + case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: + return true; + default: + break; + } /* Not a built-in. */ return false; } -- cgit v1.1 From 05bcef5a88b34dd13179cabbe902e9135cb40ffe Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 31 Jul 2021 09:35:25 +0200 Subject: openmp: Handle OpenMP directives in attribute syntax in attribute-declaration Now that we parse attribute-declaration (outside of functions), the following patch handles OpenMP directives in its attribute(s). What needs handling incrementally is diagnose mismatching begin/end pair like [[omp::directive (declare target)]]; int a; #pragma omp end declare target or #pragma omp declare target int b; [[omp::directive (end declare target)]]; and handling declare simd/declare variant on declarations (function definitions and declarations), for those in two different spots. 2021-07-31 Jakub Jelinek * parser.c (cp_parser_declaration): Handle OpenMP directives in attribute-declaration. * g++.dg/gomp/attrs-9.C: New test. --- gcc/cp/parser.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ab74e9d..47bf7d9 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -14431,6 +14431,25 @@ cp_parser_declaration (cp_parser* parser, tree prefix_attrs) { location_t attrs_loc = token1->location; tree std_attrs = cp_parser_std_attribute_spec_seq (parser); + + if (std_attrs && (flag_openmp || flag_openmp_simd)) + { + gcc_assert (!parser->lexer->in_omp_attribute_pragma); + std_attrs = cp_parser_handle_statement_omp_attributes (parser, + std_attrs); + if (parser->lexer->in_omp_attribute_pragma) + { + cp_lexer *lexer = parser->lexer; + while (parser->lexer->in_omp_attribute_pragma) + { + gcc_assert (cp_lexer_next_token_is (parser->lexer, + CPP_PRAGMA)); + cp_parser_pragma (parser, pragma_external, NULL); + } + cp_lexer_destroy (lexer); + } + } + if (std_attrs != NULL_TREE) warning_at (make_location (attrs_loc, attrs_loc, parser->lexer), OPT_Wattributes, "attribute ignored"); -- cgit v1.1 From 5b759cdcb7f863520346e5bf63fcf1d3746c2cc3 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 10 Jul 2021 05:45:02 -0400 Subject: c++: pretty-print TYPE_PACK_EXPANSION better gcc/cp/ChangeLog: * ptree.c (cxx_print_type) [TYPE_PACK_EXPANSION]: Also print PACK_EXPANSION_PATTERN. --- gcc/cp/ptree.c | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c index 33b73fb..7f140f5 100644 --- a/gcc/cp/ptree.c +++ b/gcc/cp/ptree.c @@ -171,6 +171,7 @@ cxx_print_type (FILE *file, tree node, int indent) return; case TYPE_PACK_EXPANSION: + print_node (file, "pattern", PACK_EXPANSION_PATTERN (node), indent + 4); print_node (file, "args", PACK_EXPANSION_EXTRA_ARGS (node), indent + 4); return; -- cgit v1.1 From af76342b444948ab262b276cdf083c2d2e0cebbb Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 30 Jul 2021 16:49:03 -0400 Subject: c++: ICE on anon struct with base [PR96636] pinski pointed out that my recent change to reject anonymous structs with bases was relevant to this PR. But we still ICEd after giving that error; this fixes the ICE. PR c++/96636 gcc/cp/ChangeLog: * decl.c (fixup_anonymous_aggr): Clear TYPE_NEEDS_CONSTRUCTING after error. gcc/testsuite/ChangeLog: * g++.dg/ext/anon-struct9.C: New test. --- gcc/cp/decl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index e4be6be..6fa6b9a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5094,7 +5094,11 @@ fixup_anonymous_aggr (tree t) tree field, type; if (BINFO_N_BASE_BINFOS (TYPE_BINFO (t))) - error_at (location_of (t), "anonymous struct with base classes"); + { + error_at (location_of (t), "anonymous struct with base classes"); + /* Avoid ICE after error on anon-struct9.C. */ + TYPE_NEEDS_CONSTRUCTING (t) = false; + } for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL) -- cgit v1.1 From f48c3cd2e3f9cd9e3c329eb2d3185bd26e7c7607 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 2 Aug 2021 09:59:56 -0400 Subject: c++: Improve memory usage of subsumption [PR100828] Constraint subsumption is implemented in two steps. The first step computes the disjunctive (or conjunctive) normal form of one of the constraints, and the second step verifies that each clause in the decomposed form implies the other constraint. Performing these two steps separately is problematic because in the first step the DNF/CNF can be exponentially larger than the original constraint, and by computing it ahead of time we'd have to keep all of it in memory. This patch fixes this exponential blowup in memory usage by interleaving the two steps, so that as soon as we decompose one clause we check implication for it. In turn, memory usage during subsumption is now worst case linear in the size of the constraints rather than exponential, and so we can safely remove the hard limit of 16 clauses without introducing runaway memory usage on some inputs. (Note the _time_ complexity of subsumption is still exponential in the worst case.) In order for this to work we need to make formula::branch() insert the copy of the current clause directly after the current clause rather than at the end of the list, so that we fully decompose a clause shortly after creating it. Otherwise we'd end up accumulating exponentially many (partially decomposed) clauses in memory anyway. PR c++/100828 gcc/cp/ChangeLog: * logic.cc (formula::formula): Use emplace_back instead of push_back. (formula::branch): Insert a copy of m_current directly after m_current instead of at the end of the list. (formula::erase): Define. (decompose_formula): Remove. (decompose_antecedents): Remove. (decompose_consequents): Remove. (derive_proofs): Remove. (max_problem_size): Remove. (diagnose_constraint_size): Remove. (subsumes_constraints_nonnull): Rewrite directly in terms of decompose_clause and derive_proof, interleaving decomposition with implication checking. Remove limit on constraint complexity. Use formula::erase to free the current clause before moving on to the next one. --- gcc/cp/logic.cc | 118 +++++++++++++++++--------------------------------------- 1 file changed, 35 insertions(+), 83 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/logic.cc b/gcc/cp/logic.cc index 142457e..9d892b1 100644 --- a/gcc/cp/logic.cc +++ b/gcc/cp/logic.cc @@ -223,9 +223,7 @@ struct formula formula (tree t) { - /* This should call emplace_back(). There's an extra copy being - invoked by using push_back(). */ - m_clauses.push_back (t); + m_clauses.emplace_back (t); m_current = m_clauses.begin (); } @@ -248,8 +246,7 @@ struct formula clause& branch () { gcc_assert (!done ()); - m_clauses.push_back (*m_current); - return m_clauses.back (); + return *m_clauses.insert (std::next (m_current), *m_current); } /* Returns the position of the current clause. */ @@ -287,6 +284,14 @@ struct formula return m_clauses.end (); } + /* Remove the specified clause from the formula. */ + + void erase (iterator i) + { + gcc_assert (i != m_current); + m_clauses.erase (i); + } + std::list m_clauses; /* The list of clauses. */ iterator m_current; /* The current clause. */ }; @@ -659,39 +664,6 @@ decompose_clause (formula& f, clause& c, rules r) f.advance (); } -/* Decompose the logical formula F according to the logical - rules determined by R. The result is a formula containing - clauses that contain only atomic terms. */ - -void -decompose_formula (formula& f, rules r) -{ - while (!f.done ()) - decompose_clause (f, *f.current (), r); -} - -/* Fully decomposing T into a list of sequents, each comprised of - a list of atomic constraints, as if T were an antecedent. */ - -static formula -decompose_antecedents (tree t) -{ - formula f (t); - decompose_formula (f, left); - return f; -} - -/* Fully decomposing T into a list of sequents, each comprised of - a list of atomic constraints, as if T were a consequent. */ - -static formula -decompose_consequents (tree t) -{ - formula f (t); - decompose_formula (f, right); - return f; -} - static bool derive_proof (clause&, tree, rules); /* Derive a proof of both operands of T. */ @@ -744,28 +716,6 @@ derive_proof (clause& c, tree t, rules r) } } -/* Derive a proof of T from disjunctive clauses in F. */ - -static bool -derive_proofs (formula& f, tree t, rules r) -{ - for (formula::iterator i = f.begin(); i != f.end(); ++i) - if (!derive_proof (*i, t, r)) - return false; - return true; -} - -/* The largest number of clauses in CNF or DNF we accept as input - for subsumption. This an upper bound of 2^16 expressions. */ -static int max_problem_size = 16; - -static inline bool -diagnose_constraint_size (tree t) -{ - error_at (input_location, "%qE exceeds the maximum constraint complexity", t); - return false; -} - /* Key/value pair for caching subsumption results. This associates a pair of constraints with a boolean value indicating the result. */ @@ -845,31 +795,33 @@ subsumes_constraints_nonnull (tree lhs, tree rhs) if (bool *b = lookup_subsumption(lhs, rhs)) return *b; - int n1 = dnf_size (lhs); - int n2 = cnf_size (rhs); - - /* Make sure we haven't exceeded the largest acceptable problem. */ - if (std::min (n1, n2) >= max_problem_size) - { - if (n1 < n2) - diagnose_constraint_size (lhs); - else - diagnose_constraint_size (rhs); - return false; - } - - /* Decompose the smaller of the two formulas, and recursively - check for implication of the larger. */ - bool result; - if (n1 <= n2) - { - formula dnf = decompose_antecedents (lhs); - result = derive_proofs (dnf, rhs, left); - } + tree x, y; + rules r; + if (dnf_size (lhs) <= cnf_size (rhs)) + /* When LHS looks simpler than RHS, we'll determine subsumption by + decomposing LHS into its disjunctive normal form and checking that + each (conjunctive) clause in the decomposed LHS implies RHS. */ + x = lhs, y = rhs, r = left; else + /* Otherwise, we'll determine subsumption by decomposing RHS into its + conjunctive normal form and checking that each (disjunctive) clause + in the decomposed RHS implies LHS. */ + x = rhs, y = lhs, r = right; + + /* Decompose X into a list of sequents according to R, and recursively + check for implication of Y. */ + bool result = true; + formula f (x); + while (!f.done ()) { - formula cnf = decompose_consequents (rhs); - result = derive_proofs (cnf, lhs, right); + auto i = f.current (); + decompose_clause (f, *i, r); + if (!derive_proof (*i, y, r)) + { + result = false; + break; + } + f.erase (i); } return save_subsumption (lhs, rhs, result); -- cgit v1.1 From 4d17ca1bc74109e5cc4ef34890b6293c4bcb1d6a Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 3 Aug 2021 07:49:16 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 27323bb..5468792 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,93 @@ +2021-08-02 Patrick Palka + + PR c++/100828 + * logic.cc (formula::formula): Use emplace_back instead of + push_back. + (formula::branch): Insert a copy of m_current directly after + m_current instead of at the end of the list. + (formula::erase): Define. + (decompose_formula): Remove. + (decompose_antecedents): Remove. + (decompose_consequents): Remove. + (derive_proofs): Remove. + (max_problem_size): Remove. + (diagnose_constraint_size): Remove. + (subsumes_constraints_nonnull): Rewrite directly in terms of + decompose_clause and derive_proof, interleaving decomposition + with implication checking. Remove limit on constraint complexity. + Use formula::erase to free the current clause before moving on to + the next one. + +2021-07-31 Jason Merrill + + PR c++/96636 + * decl.c (fixup_anonymous_aggr): Clear TYPE_NEEDS_CONSTRUCTING + after error. + +2021-07-31 Jason Merrill + + * ptree.c (cxx_print_type) [TYPE_PACK_EXPANSION]: Also print + PACK_EXPANSION_PATTERN. + +2021-07-31 Jakub Jelinek + + * parser.c (cp_parser_declaration): Handle OpenMP directives + in attribute-declaration. + +2021-07-30 Jakub Jelinek + + PR c++/101539 + * 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. + +2021-07-30 Jason Merrill + + * class.c (finish_struct_anon): Improve comment. + * decl.c (fixup_anonymous_aggr): Reject anonymous struct + with bases. + +2021-07-30 Jakub Jelinek + + * parser.c (cp_parser_statement): Rollback attributes not just + when std_attrs is non-NULL, but whenever + cp_parser_std_attribute_spec_seq parsed any tokens. + +2021-07-30 Jakub Jelinek + + PR c++/101582 + * parser.c (cp_parser_skip_std_attribute_spec_seq): Add a forward + declaration. + (cp_parser_declaration): Parse empty-declaration and + attribute-declaration. + (cp_parser_toplevel_declaration): Don't parse empty-declaration here. + 2021-07-28 Martin Sebor * init.c: Include new header. -- cgit v1.1 From af31cab04770f7a1a1da069415ab62ca2ef54fc4 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 4 Aug 2021 11:53:48 +0200 Subject: c++: Fix up #pragma omp declare {simd,variant} and acc routine parsing When parsing default arguments, we need to temporarily clear parser->omp_declare_simd and parser->oacc_routine, otherwise it can clash with further declarations inside of e.g. lambdas inside of those default arguments. 2021-08-04 Jakub Jelinek PR c++/101759 * parser.c (cp_parser_default_argument): Temporarily override parser->omp_declare_simd and parser->oacc_routine to NULL. * g++.dg/gomp/pr101759.C: New test. * g++.dg/goacc/pr101759.C: New test. --- gcc/cp/parser.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 47bf7d9..02ce954 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -24488,6 +24488,8 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p) set correctly. */ saved_greater_than_is_operator_p = parser->greater_than_is_operator_p; parser->greater_than_is_operator_p = !template_parm_p; + auto odsd = make_temp_override (parser->omp_declare_simd, NULL); + auto ord = make_temp_override (parser->oacc_routine, NULL); /* Local variable names (and the `this' keyword) may not appear in a default argument. */ saved_local_variables_forbidden_p = parser->local_variables_forbidden_p; -- cgit v1.1 From 2697f8324fbb09b0d92036ba6a6b8a2b8d256b23 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 5 Aug 2021 00:17:03 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5468792..5b3e191 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2021-08-04 Jakub Jelinek + + PR c++/101759 + * parser.c (cp_parser_default_argument): Temporarily override + parser->omp_declare_simd and parser->oacc_routine to NULL. + 2021-08-02 Patrick Palka PR c++/100828 -- cgit v1.1 From 6b0bde7eef492843426c3f6b2da229b3c1526eaa Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Fri, 6 Aug 2021 12:21:05 +0100 Subject: middle-end/AArch64: Fix bootstrap after vec changes The build is broken since a3d3e8c362c2 since it's deleted the ability to pass vec<> by value and now must be past by reference. However some language hooks used by AArch64 were not updated and breaks the build on AArch64. This patch updates these hooks. gcc/c/ChangeLog: * c-decl.c (c_simulate_enum_decl): Pass vec<> by pointer. * c-tree.h (c_simulate_enum_decl): Likewise. gcc/ChangeLog: * config/aarch64/aarch64-sve-builtins.cc (register_svpattern, register_svprfop): Pass vec<> by pointer. * langhooks-def.h (lhd_simulate_enum_decl): Likewise. * langhooks.c (lhd_simulate_enum_decl): Likewise. * langhooks.h (struct lang_hooks_for_types): Likewise. gcc/cp/ChangeLog: * cp-objcp-common.h (cxx_simulate_enum_decl): Pass vec<> by pointer. * decl.c (cxx_simulate_enum_decl): Likewise. --- gcc/cp/cp-objcp-common.h | 2 +- gcc/cp/decl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index 53c6e4c..f1704aa 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -38,7 +38,7 @@ extern bool cp_handle_option (size_t, const char *, HOST_WIDE_INT, int, location_t, const struct cl_option_handlers *); extern tree cxx_make_type_hook (tree_code); extern tree cxx_simulate_enum_decl (location_t, const char *, - vec); + vec *); /* Lang hooks that are shared between C++ and ObjC++ are defined here. Hooks specific to C++ or ObjC++ go in cp/cp-lang.c and objcp/objcp-lang.c, diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6fa6b9a..f626f1e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -16408,7 +16408,7 @@ lookup_enumerator (tree enumtype, tree name) tree cxx_simulate_enum_decl (location_t loc, const char *name, - vec values) + vec *values) { location_t saved_loc = input_location; input_location = loc; -- cgit v1.1 From f92f47785201d44cef91e2c4a9742fb503ce5316 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 7 Aug 2021 00:16:39 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5b3e191..a8f70b0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2021-08-06 Tamar Christina + + * cp-objcp-common.h (cxx_simulate_enum_decl): Pass vec<> by pointer. + * decl.c (cxx_simulate_enum_decl): Likewise. + 2021-08-04 Jakub Jelinek PR c++/101759 -- cgit v1.1 From c40c6a50fd4da342c87a715ae83927a37797e094 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 10 Aug 2021 11:22:33 +0200 Subject: openmp: Add support for declare simd and declare variant in a attribute syntax This patch adds support for declare simd and declare variant in attribute syntax. Either in attribute-specifier-seq at the start of declaration, in that case it has similar restriction to pragma-syntax, that there is a single function declaration/definition in the declaration, rather than variable declaration or more than one function declarations or mix of function and variable declarations. Or after the declarator id, in that case it applies just to the single function declaration and the same declaration can have multiple such attributes. Or both. Furthermore, cp_parser_statement has been adjusted so that it doesn't accept [[omp::directive (parallel)]] etc. before statements that don't take attributes at all, or where those attributes don't appertain to the statement but something else (e.g. to label, using directive, declaration, etc.). 2021-08-10 Jakub Jelinek gcc/cp/ * parser.h (struct cp_omp_declare_simd_data): Remove in_omp_attribute_pragma and clauses members, add loc and attribs. (struct cp_oacc_routine_data): Remove loc member, add clauses member. * parser.c (cp_finalize_omp_declare_simd): New function. (cp_parser_handle_statement_omp_attributes): Mention in function comment the function is used also for attribute-declaration. (cp_parser_handle_directive_omp_attributes): New function. (cp_parser_statement): Don't call cp_parser_handle_statement_omp_attributes if statement doesn't have attribute-specifier-seq at the beginning at all or if if those attributes don't appertain to the statement. (cp_parser_simple_declaration): Call cp_parser_handle_directive_omp_attributes and cp_finalize_omp_declare_simd. (cp_parser_explicit_instantiation): Likewise. (cp_parser_init_declarator): Initialize prefix_attributes only after parsing declarators. (cp_parser_direct_declarator): Call cp_parser_handle_directive_omp_attributes and cp_finalize_omp_declare_simd. (cp_parser_member_declaration): Likewise. (cp_parser_single_declaration): Likewise. (cp_parser_omp_declare_simd): Don't initialize data.in_omp_attribute_pragma, instead initialize data.attribs[0] and data.attribs[1]. (cp_finish_omp_declare_variant): Remove in_omp_attribute_pragma argument, instead use parser->lexer->in_omp_attribute_pragma. (cp_parser_late_parsing_omp_declare_simd): Adjust cp_finish_omp_declare_variant caller. Handle attribute-syntax declare simd/variant. gcc/testsuite/ * g++.dg/gomp/attrs-1.C (bar): Add missing semicolon after [[omp::directive (threadprivate (t2))]]. Add tests with if/while/switch after parallel in attribute syntax. (corge): Add missing omp:: before directive. * g++.dg/gomp/attrs-2.C (bar): Add missing semicolon after [[omp::directive (threadprivate (t2))]]. * g++.dg/gomp/attrs-10.C: New test. * g++.dg/gomp/attrs-11.C: New test. --- gcc/cp/parser.c | 419 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- gcc/cp/parser.h | 7 +- 2 files changed, 401 insertions(+), 25 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 02ce954..34be15e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1440,6 +1440,24 @@ cp_finalize_omp_declare_simd (cp_parser *parser, tree fndecl) } } +/* Similarly, but for use in declaration parsing functions + which call cp_parser_handle_directive_omp_attributes. */ + +static inline void +cp_finalize_omp_declare_simd (cp_parser *parser, cp_omp_declare_simd_data *data) +{ + if (parser->omp_declare_simd != data) + return; + + if (!parser->omp_declare_simd->error_seen + && !parser->omp_declare_simd->fndecl_seen) + error_at (parser->omp_declare_simd->loc, + "% directive not immediately followed by " + "function declaration or definition", + parser->omp_declare_simd->variant_p ? "variant" : "simd"); + parser->omp_declare_simd = NULL; +} + /* Diagnose if #pragma acc routine isn't followed immediately by function declaration or definition. */ @@ -11661,7 +11679,7 @@ struct cp_omp_attribute_data }; /* Handle omp::directive and omp::sequence attributes in ATTRS - (if any) at the start of a statement. */ + (if any) at the start of a statement or in attribute-declaration. */ static tree cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) @@ -11858,6 +11876,98 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) return attrs; } +/* Handle omp::directive and omp::sequence attributes in *PATTRS + (if any) at the start or after declaration-id of a declaration. */ + +static void +cp_parser_handle_directive_omp_attributes (cp_parser *parser, tree *pattrs, + cp_omp_declare_simd_data *data, + bool start) +{ + if (!flag_openmp && !flag_openmp_simd) + return; + + int cnt = 0; + bool bad = false; + bool variant_p = false; + location_t loc = UNKNOWN_LOCATION; + for (tree pa = *pattrs; pa; pa = TREE_CHAIN (pa)) + if (get_attribute_namespace (pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (pa))) + { + for (tree a = TREE_VALUE (pa); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + const char *directive[3] = {}; + for (int i = 0; i < 3; i++) + { + tree id = NULL_TREE; + if (first + i == last) + break; + if (first[i].type == CPP_NAME) + id = first[i].u.value; + else if (first[i].type == CPP_KEYWORD) + id = ridpointers[(int) first[i].keyword]; + else + break; + directive[i] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + continue; + if (dir->id == PRAGMA_OMP_DECLARE + && (strcmp (directive[1], "simd") == 0 + || strcmp (directive[1], "variant") == 0)) + { + if (cnt++ == 0) + { + variant_p = strcmp (directive[1], "variant") == 0; + loc = first->location; + } + if (start && parser->omp_declare_simd && !bad) + { + error_at (first->location, + "mixing OpenMP directives with attribute and " + "pragma syntax on the same declaration"); + bad = true; + } + } + } + } + + if (bad) + { + for (tree *pa = pattrs; *pa; ) + if (get_attribute_namespace (*pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (*pa))) + *pa = TREE_CHAIN (*pa); + else + pa = &TREE_CHAIN (*pa); + return; + } + if (cnt == 0) + return; + + if (parser->omp_declare_simd == NULL) + { + data->error_seen = false; + data->fndecl_seen = false; + data->variant_p = variant_p; + data->loc = loc; + data->tokens = vNULL; + data->attribs[0] = NULL; + data->attribs[1] = NULL; + parser->omp_declare_simd = data; + } + parser->omp_declare_simd->attribs[!start] = pattrs; +} + /* Parse a statement. statement: @@ -11935,12 +12045,57 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, } has_std_attrs = cp_lexer_peek_token (parser->lexer) != token; + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + bool omp_attrs_forbidden_p; + omp_attrs_forbidden_p = parser->omp_attrs_forbidden_p; + if (std_attrs && (flag_openmp || flag_openmp_simd)) - std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs); + { + bool handle_omp_attribs = false; + if (token->type == CPP_KEYWORD) + switch (token->keyword) + { + case RID_IF: + case RID_SWITCH: + case RID_WHILE: + case RID_DO: + case RID_FOR: + case RID_BREAK: + case RID_CONTINUE: + case RID_RETURN: + case RID_CO_RETURN: + case RID_GOTO: + case RID_AT_TRY: + case RID_AT_CATCH: + case RID_AT_FINALLY: + case RID_AT_SYNCHRONIZED: + case RID_AT_THROW: + case RID_TRY: + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + case RID_SYNCHRONIZED: + case RID_ATOMIC_NOEXCEPT: + case RID_ATOMIC_CANCEL: + case RID_TRANSACTION_CANCEL: + handle_omp_attribs = true; + break; + default: + break; + } + else if (token->type == CPP_SEMICOLON + || token->type == CPP_OPEN_BRACE + || token->type == CPP_PRAGMA) + handle_omp_attribs = true; + if (handle_omp_attribs) + { + std_attrs = cp_parser_handle_statement_omp_attributes (parser, + std_attrs); + token = cp_lexer_peek_token (parser->lexer); + } + } parser->omp_attrs_forbidden_p = false; - /* Peek at the next token. */ - token = cp_lexer_peek_token (parser->lexer); /* Remember the location of the first token in the statement. */ cp_token *statement_token = token; statement_location = token->location; @@ -12058,6 +12213,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, a statement all its own. */ else if (token->type == CPP_PRAGMA) { + do_pragma:; cp_lexer *lexer = parser->lexer; bool do_restart = false; /* Only certain OpenMP pragmas are attached to statements, and thus @@ -12120,7 +12276,46 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, return; /* It didn't work, restore the post-attribute position. */ if (has_std_attrs) - cp_lexer_set_token_position (parser->lexer, statement_token); + { + cp_lexer_set_token_position (parser->lexer, statement_token); + if (flag_openmp || flag_openmp_simd) + { + size_t i = 1; + bool handle_omp_attribs = true; + while (cp_lexer_peek_nth_token (parser->lexer, i)->keyword + == RID_EXTENSION) + i++; + switch (cp_lexer_peek_nth_token (parser->lexer, i)->keyword) + { + case RID_ASM: + case RID_NAMESPACE: + case RID_USING: + case RID_LABEL: + case RID_STATIC_ASSERT: + /* Don't handle OpenMP attribs on keywords that + always start a declaration statement but don't + accept attribute before it and therefore + the tentative cp_parser_declaration_statement + fails to parse because of that. */ + handle_omp_attribs = false; + break; + default: + break; + } + + if (handle_omp_attribs) + { + parser->omp_attrs_forbidden_p = omp_attrs_forbidden_p; + std_attrs + = cp_parser_handle_statement_omp_attributes + (parser, std_attrs); + parser->omp_attrs_forbidden_p = false; + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_PRAGMA) + goto do_pragma; + } + } + } } /* All preceding labels have been parsed at this point. */ if (loc_after_labels != NULL) @@ -14770,6 +14965,12 @@ cp_parser_simple_declaration (cp_parser* parser, /* We no longer need to defer access checks. */ stop_deferring_access_checks (); + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* In a block scope, a valid declaration must always have a decl-specifier-seq. By not trying to parse declarators, we can resolve the declaration/expression ambiguity more quickly. */ @@ -14962,6 +15163,7 @@ cp_parser_simple_declaration (cp_parser* parser, else { pop_deferring_access_checks (); + cp_finalize_omp_declare_simd (parser, &odsd); return; } } @@ -15042,6 +15244,7 @@ cp_parser_simple_declaration (cp_parser* parser, done: pop_deferring_access_checks (); + cp_finalize_omp_declare_simd (parser, &odsd); } /* Helper of cp_parser_simple_declaration, parse a decomposition declaration. @@ -18659,6 +18862,13 @@ cp_parser_explicit_instantiation (cp_parser* parser) CP_PARSER_FLAGS_OPTIONAL, &decl_specifiers, &declares_class_or_enum); + + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* If there was exactly one decl-specifier, and it declared a class, and there's no declarator, then we have an explicit type instantiation. */ @@ -18727,6 +18937,8 @@ cp_parser_explicit_instantiation (cp_parser* parser) cp_parser_consume_semicolon_at_end_of_statement (parser); timevar_pop (TV_TEMPLATE_INST); + + cp_finalize_omp_declare_simd (parser, &odsd); } /* Parse an explicit-specialization. @@ -21964,10 +22176,6 @@ cp_parser_init_declarator (cp_parser* parser, if (decl_spec_seq_has_spec_p (decl_specifiers, ds_consteval)) flags |= CP_PARSER_FLAGS_CONSTEVAL; - /* Gather the attributes that were provided with the - decl-specifiers. */ - prefix_attributes = decl_specifiers->attributes; - /* Assume that this is not the declarator for a function definition. */ if (function_definition_p) @@ -22031,6 +22239,10 @@ cp_parser_init_declarator (cp_parser* parser, else asm_specification = NULL_TREE; + /* Gather the attributes that were provided with the + decl-specifiers. */ + prefix_attributes = decl_specifiers->attributes; + /* Look for attributes. */ attributes_start_token = cp_lexer_peek_token (parser->lexer); attributes = cp_parser_attributes_opt (parser); @@ -22679,13 +22891,27 @@ cp_parser_direct_declarator (cp_parser* parser, attrs = cp_parser_std_attribute_spec_seq (parser); + cp_omp_declare_simd_data odsd; + if ((flag_openmp || flag_openmp_simd) + && declarator + && declarator->std_attributes + && declarator->kind == cdk_id) + { + tree *pa = &declarator->std_attributes; + cp_parser_handle_directive_omp_attributes (parser, pa, + &odsd, false); + } + /* In here, we handle cases where attribute is used after the function declaration. For example: void func (int x) __attribute__((vector(..))); */ tree gnu_attrs = NULL_TREE; tree requires_clause = NULL_TREE; - late_return = (cp_parser_late_return_type_opt - (parser, declarator, requires_clause)); + late_return + = cp_parser_late_return_type_opt (parser, declarator, + requires_clause); + + cp_finalize_omp_declare_simd (parser, &odsd); /* Parse the virt-specifier-seq. */ virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); @@ -26435,6 +26661,13 @@ cp_parser_member_declaration (cp_parser* parser) | CP_PARSER_FLAGS_TYPENAME_OPTIONAL), &decl_specifiers, &declares_class_or_enum); + + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* Check for an invalid type-name. */ if (!decl_specifiers.any_type_specifiers_p && cp_parser_parse_and_diagnose_invalid_type_name (parser)) @@ -26554,6 +26787,10 @@ cp_parser_member_declaration (cp_parser* parser) being declared. */ prefix_attributes = decl_specifiers.attributes; decl_specifiers.attributes = NULL_TREE; + if (parser->omp_declare_simd + && (parser->omp_declare_simd->attribs[0] + == &decl_specifiers.attributes)) + parser->omp_declare_simd->attribs[0] = &prefix_attributes; /* See if these declarations will be friends. */ friend_p = cp_parser_friend_p (&decl_specifiers); @@ -26942,6 +27179,7 @@ cp_parser_member_declaration (cp_parser* parser) cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); out: parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + cp_finalize_omp_declare_simd (parser, &odsd); } /* Parse a pure-specifier. @@ -31067,6 +31305,13 @@ cp_parser_single_declaration (cp_parser* parser, | CP_PARSER_FLAGS_TYPENAME_OPTIONAL), &decl_specifiers, &declares_class_or_enum); + + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + if (friend_p) *friend_p = cp_parser_friend_p (&decl_specifiers); @@ -31195,6 +31440,8 @@ cp_parser_single_declaration (cp_parser* parser, parser->qualifying_scope = NULL_TREE; parser->object_scope = NULL_TREE; + cp_finalize_omp_declare_simd (parser, &odsd); + return decl; } @@ -43546,9 +43793,10 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, data.error_seen = false; data.fndecl_seen = false; data.variant_p = variant_p; - data.in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; data.tokens = vNULL; - data.clauses = NULL_TREE; + data.attribs[0] = NULL; + data.attribs[1] = NULL; + data.loc = UNKNOWN_LOCATION; /* It is safe to take the address of a local variable; it will only be used while this scope is live. */ parser->omp_declare_simd = &data; @@ -43985,7 +44233,7 @@ cp_parser_omp_context_selector_specification (cp_parser *parser, static tree cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, - tree attrs, bool in_omp_attribute_pragma) + tree attrs) { matching_parens parens; if (!parens.require_open (parser)) @@ -44044,7 +44292,7 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, location_t varid_loc = make_location (caret_loc, start_loc, finish_loc); /* For now only in C++ attributes, do it always for OpenMP 5.1. */ - if (in_omp_attribute_pragma + if (parser->lexer->in_omp_attribute_pragma && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) cp_lexer_consume_token (parser->lexer); @@ -44121,11 +44369,10 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) cp_lexer_consume_token (parser->lexer); if (strcmp (kind, "simd") == 0) { - /* For now only in C++ attributes, do it always for OpenMP 5.1. */ - if (data->in_omp_attribute_pragma - && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + /* For now only in C++ attributes, do it always for OpenMP 5.1. + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) - cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); */ cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, "#pragma omp declare simd", @@ -44142,12 +44389,142 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) { gcc_assert (strcmp (kind, "variant") == 0); attrs - = cp_finish_omp_declare_variant (parser, pragma_tok, attrs, - data->in_omp_attribute_pragma); + = cp_finish_omp_declare_variant (parser, pragma_tok, attrs); } cp_parser_pop_lexer (parser); } + cp_lexer *lexer = NULL; + for (int i = 0; i < 2; i++) + { + if (data->attribs[i] == NULL) + continue; + for (tree *pa = data->attribs[i]; *pa; ) + if (get_attribute_namespace (*pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (*pa))) + { + for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + const char *directive[3] = {}; + for (int j = 0; j < 3; j++) + { + tree id = NULL_TREE; + if (first + j == last) + break; + if (first[j].type == CPP_NAME) + id = first[j].u.value; + else if (first[j].type == CPP_KEYWORD) + id = ridpointers[(int) first[j].keyword]; + else + break; + directive[j] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + { + error_at (first->location, + "unknown OpenMP directive name in " + "% attribute argument"); + continue; + } + if (dir->id != PRAGMA_OMP_DECLARE + || (strcmp (directive[1], "simd") != 0 + && strcmp (directive[1], "variant") != 0)) + { + error_at (first->location, + "OpenMP directive other than % " + "or % appertains to a " + "declaration"); + continue; + } + + if (!flag_openmp && strcmp (directive[1], "simd") != 0) + continue; + if (lexer == NULL) + { + lexer = cp_lexer_alloc (); + lexer->debugging_p = parser->lexer->debugging_p; + } + vec_safe_reserve (lexer->buffer, (last - first) + 2); + cp_token tok = {}; + tok.type = CPP_PRAGMA; + tok.keyword = RID_MAX; + tok.u.value = build_int_cst (NULL, PRAGMA_OMP_DECLARE); + tok.location = first->location; + lexer->buffer->quick_push (tok); + while (++first < last) + lexer->buffer->quick_push (*first); + tok = {}; + tok.type = CPP_PRAGMA_EOL; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + tok = {}; + tok.type = CPP_EOF; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + lexer->next = parser->lexer; + lexer->next_token = lexer->buffer->address (); + lexer->last_token = lexer->next_token + + lexer->buffer->length () + - 1; + lexer->in_omp_attribute_pragma = true; + parser->lexer = lexer; + /* Move the current source position to that of the first token + in the new lexer. */ + cp_lexer_set_source_position_from_token (lexer->next_token); + + cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer); + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *kind = IDENTIFIER_POINTER (id); + cp_lexer_consume_token (parser->lexer); + + tree c, cl; + if (strcmp (kind, "simd") == 0) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + + omp_clause_mask mask = OMP_DECLARE_SIMD_CLAUSE_MASK; + cl = cp_parser_omp_all_clauses (parser, mask, + "#pragma omp declare simd", + pragma_tok); + if (cl) + cl = tree_cons (NULL_TREE, cl, NULL_TREE); + c = build_tree_list (get_identifier ("omp declare simd"), + cl); + TREE_CHAIN (c) = attrs; + if (processing_template_decl) + ATTR_IS_DEPENDENT (c) = 1; + attrs = c; + } + else + { + gcc_assert (strcmp (kind, "variant") == 0); + attrs + = cp_finish_omp_declare_variant (parser, pragma_tok, + attrs); + } + gcc_assert (parser->lexer != lexer); + vec_safe_truncate (lexer->buffer, 0); + } + *pa = TREE_CHAIN (*pa); + } + else + pa = &TREE_CHAIN (*pa); + } + if (lexer) + cp_lexer_destroy (lexer); + data->fndecl_seen = true; return attrs; } diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index e62742d..3669587 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -216,15 +216,14 @@ struct cp_omp_declare_simd_data { bool error_seen; /* Set if error has been reported. */ bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */ bool variant_p; /* Set for #pragma omp declare variant. */ - bool in_omp_attribute_pragma; /* True if declare simd/variant comes from - C++11 attribute rather than pragma. */ + location_t loc; vec tokens; - tree clauses; + tree *attribs[2]; }; /* Helper data structure for parsing #pragma acc routine. */ struct cp_oacc_routine_data : cp_omp_declare_simd_data { - location_t loc; + tree clauses; }; /* The cp_parser structure represents the C++ parser. */ -- cgit v1.1 From d796cc7a3e719cc36f1851ca322e2877b974691b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 10 Aug 2021 18:01:23 +0200 Subject: openmp: Fix up cp/parser.c build with GCC 4.8 to 6 Christophe Lyon reported that cp/parser.c no longer compiles with GCC 4.8.5 after my recent OpenMP changes. A goto out; there crosses odsd variable declaration, and odsd has a vec<...> member where vec has = default; default constructor and gcc before r7-2822-gd0b0fbd9fce2f30a82558bf2308b3a7b56c2f364 treated that as error. Fixed by moving the declaration earlier before the goto. Tested on x86_64-linux with GCC 4.8.5 system gcc, committed to trunk as obvious. 2021-08-10 Jakub Jelinek * parser.c (cp_parser_member_declaration): Move odsd declaration before cp_parser_using_declaration call to avoid errors with GCC 4.8 to 6. --- gcc/cp/parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 34be15e..1be42a1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -26651,8 +26651,9 @@ cp_parser_member_declaration (cp_parser* parser) parser->colon_corrects_to_scope_p = false; + cp_omp_declare_simd_data odsd; if (cp_parser_using_declaration (parser, /*access_declaration=*/true)) - goto out; + goto out; /* Parse the decl-specifier-seq. */ decl_spec_token_start = cp_lexer_peek_token (parser->lexer); @@ -26662,7 +26663,6 @@ cp_parser_member_declaration (cp_parser* parser) &decl_specifiers, &declares_class_or_enum); - cp_omp_declare_simd_data odsd; if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) cp_parser_handle_directive_omp_attributes (parser, &decl_specifiers.attributes, -- cgit v1.1 From 3ae564ea7410e99e533bc87f999a04b2647c831d Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 11 Aug 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a8f70b0..fbd4af2e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,45 @@ +2021-08-10 Jakub Jelinek + + * parser.c (cp_parser_member_declaration): Move odsd declaration + before cp_parser_using_declaration call to avoid errors with + GCC 4.8 to 6. + +2021-08-10 Jakub Jelinek + + * parser.h (struct cp_omp_declare_simd_data): Remove + in_omp_attribute_pragma and clauses members, add loc and attribs. + (struct cp_oacc_routine_data): Remove loc member, add clauses + member. + * parser.c (cp_finalize_omp_declare_simd): New function. + (cp_parser_handle_statement_omp_attributes): Mention in + function comment the function is used also for + attribute-declaration. + (cp_parser_handle_directive_omp_attributes): New function. + (cp_parser_statement): Don't call + cp_parser_handle_statement_omp_attributes if statement doesn't + have attribute-specifier-seq at the beginning at all or if + if those attributes don't appertain to the statement. + (cp_parser_simple_declaration): Call + cp_parser_handle_directive_omp_attributes and + cp_finalize_omp_declare_simd. + (cp_parser_explicit_instantiation): Likewise. + (cp_parser_init_declarator): Initialize prefix_attributes + only after parsing declarators. + (cp_parser_direct_declarator): Call + cp_parser_handle_directive_omp_attributes and + cp_finalize_omp_declare_simd. + (cp_parser_member_declaration): Likewise. + (cp_parser_single_declaration): Likewise. + (cp_parser_omp_declare_simd): Don't initialize + data.in_omp_attribute_pragma, instead initialize + data.attribs[0] and data.attribs[1]. + (cp_finish_omp_declare_variant): Remove + in_omp_attribute_pragma argument, instead use + parser->lexer->in_omp_attribute_pragma. + (cp_parser_late_parsing_omp_declare_simd): Adjust + cp_finish_omp_declare_variant caller. Handle attribute-syntax + declare simd/variant. + 2021-08-06 Tamar Christina * cp-objcp-common.h (cxx_simulate_enum_decl): Pass vec<> by pointer. -- cgit v1.1 From 6186708312780bb2139da01946abdde39667e985 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 11 Aug 2021 15:58:30 -0400 Subject: c++: most vexing parse and braced CTAD [PR89062] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here grokdeclarator is emitting the error error: class template placeholder ‘Foo’ not permitted in this context during the tentative (and ultimately futile) parse of 'x' as a function declaration. This happens because when parsing 'Foo{1}', cp_parser_parameter_declaration yields a parameter declaration with no declarator and whose type is a CTAD placeholder, and stops short of consuming the '{'. The caller cp_parser_parameter_declaration_list then calls grokdeclarator on this declarator, hence the error, and soon thereafter we abort this tentative parse since the next token '{' doesn't make sense in the context of a parameter list. Note that we don't have this issue with parenthesized CTAD Foo x(Foo(1)); because in this case cp_parser_direct_declarator (called indirectly from c_p_p_d) consumes the '(' and returns cp_error_declarator instead of a NULL declarator (and also simulates a parse error), and grokdeclarator exits early for this declarator without emitting any error. Since grokdeclarator doesn't take a 'complain' parameter, to fix this we need to avoid calling grokdeclarator in this situation. To that end this patch makes c_p_p_d simulate an error when a construct is a CTAD expression and definitely not a parameter declaration, so that c_p_p_d_l can avoid calling grokdeclarator by checking for this simulated error. Alternatively we could keep all this logic inside c_p_p_d_l and not touch c_p_p_d at all, but this approach seems slightly less adhoc. PR c++/89062 gcc/cp/ChangeLog: * parser.c (cp_parser_parameter_declaration_list): Don't call grokdeclarator if cp_parser_error_occurred. (cp_parser_parameter_declaration): Simulate an error if we see the beginning of a CTAD form, i.e. if we see an opening brace after the decl-specifier-seq and the type is a CTAD placeholder. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction97.C: New test. --- gcc/cp/parser.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1be42a1..87e8d37 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -24284,7 +24284,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, cp_parser_flags flags) and warn in grokparms if appropriate. */ deprecated_state = DEPRECATED_SUPPRESS; - if (parameter) + if (parameter && !cp_parser_error_occurred (parser)) { decl = grokdeclarator (parameter->declarator, ¶meter->decl_specifiers, @@ -24499,7 +24499,7 @@ cp_parser_parameter_declaration (cp_parser *parser, parser->default_arg_ok_p = false; /* After seeing a decl-specifier-seq, if the next token is not a - "(", there is no possibility that the code is a valid + "(" or "{", there is no possibility that the code is a valid expression. Therefore, if parsing tentatively, we commit at this point. */ if (!parser->in_template_argument_list_p @@ -24512,9 +24512,18 @@ cp_parser_parameter_declaration (cp_parser *parser, of some object of type "char" to "int". */ && !parser->in_type_id_in_expr_p && cp_parser_uncommitted_to_tentative_parse_p (parser) - && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE) && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)) - cp_parser_commit_to_tentative_parse (parser); + { + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + if (decl_specifiers.type + && template_placeholder_p (decl_specifiers.type)) + /* This is a CTAD expression, not a parameter declaration. */ + cp_parser_simulate_error (parser); + } + else + cp_parser_commit_to_tentative_parse (parser); + } /* Parse the declarator. */ declarator_token_start = token; declarator = cp_parser_declarator (parser, -- cgit v1.1 From 7e39d1a15f5276f72ee478a692445569bb646e65 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 11 Aug 2021 15:59:22 -0400 Subject: c++: recognize class-scope non-template dguides [PR79501] It looks like we still don't recognize class-scope non-template deduction guides even after r12-2260. This is because deduction guides are tagged as such in cp_parser_init_declarator after calling cp_parser_declarator, but in cp_parser_member_declaration we call cp_parser_declarator directly. So let's tag them in cp_parser_member_declaration as well. PR c++/79501 gcc/cp/ChangeLog: * parser.c (maybe_adjust_declarator_for_dguide): New, split out from ... (cp_parser_init_declarator): ... here. (cp_parser_member_declaration): Use it. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction98.C: New test. --- gcc/cp/parser.c | 63 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 19 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 87e8d37..b5e117d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -22078,6 +22078,37 @@ warn_about_ambiguous_parse (const cp_decl_specifier_seq *decl_specifiers, } } +/* If DECLARATOR with DECL_SPECS is a function declarator that has + the form of a deduction guide, tag it as such. CTOR_DTOR_OR_CONV_P + has the same meaning as in cp_parser_declarator. */ + +static void +cp_parser_maybe_adjust_declarator_for_dguide (cp_parser *parser, + cp_decl_specifier_seq *decl_specs, + cp_declarator *declarator, + int *ctor_dtor_or_conv_p) +{ + if (cxx_dialect >= cxx17 + && *ctor_dtor_or_conv_p <= 0 + && !decl_specs->type + && !decl_specs->any_type_specifiers_p + && function_declarator_p (declarator)) + { + cp_declarator *id = get_id_declarator (declarator); + tree name = id->u.id.unqualified_name; + parser->scope = id->u.id.qualifying_scope; + tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc); + if (tmpl + && (DECL_CLASS_TEMPLATE_P (tmpl) + || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) + { + id->u.id.unqualified_name = dguide_name (tmpl); + id->u.id.sfk = sfk_deduction_guide; + *ctor_dtor_or_conv_p = 1; + } + } +} + /* Declarators [gram.dcl.decl] */ /* Parse an init-declarator. @@ -22254,25 +22285,13 @@ cp_parser_init_declarator (cp_parser* parser, if (function_declarator_p (declarator)) { - /* Handle C++17 deduction guides. */ - if (!decl_specifiers->type - && !decl_specifiers->any_type_specifiers_p - && ctor_dtor_or_conv_p <= 0 - && cxx_dialect >= cxx17) - { - cp_declarator *id = get_id_declarator (declarator); - tree name = id->u.id.unqualified_name; - parser->scope = id->u.id.qualifying_scope; - tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc); - if (tmpl - && (DECL_CLASS_TEMPLATE_P (tmpl) - || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) - { - id->u.id.unqualified_name = dguide_name (tmpl); - id->u.id.sfk = sfk_deduction_guide; - ctor_dtor_or_conv_p = 1; - } - } + /* Handle C++17 deduction guides. Note that class-scope + non-template deduction guides are instead handled in + cp_parser_member_declaration. */ + cp_parser_maybe_adjust_declarator_for_dguide (parser, + decl_specifiers, + declarator, + &ctor_dtor_or_conv_p); if (!member_p && !cp_parser_error_occurred (parser)) warn_about_ambiguous_parse (decl_specifiers, declarator); @@ -26956,6 +26975,12 @@ cp_parser_member_declaration (cp_parser* parser) goto out; } + /* Handle class-scope non-template C++17 deduction guides. */ + cp_parser_maybe_adjust_declarator_for_dguide (parser, + &decl_specifiers, + declarator, + &ctor_dtor_or_conv_p); + if (declares_class_or_enum & 2) cp_parser_check_for_definition_in_return_type (declarator, decl_specifiers.type, -- cgit v1.1 From ee8f9ff00d79998274c967ad0c23692be9dd3ada Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 11 Aug 2021 22:00:29 +0200 Subject: c++: Optimize constinit thread_local vars [PR101786] The paper that introduced constinit mentioned in rationale that constinit can be used on externs as well and that it can be used to avoid the thread_local initialization wrappers, because the standard requires that if constinit is present on any declaration, it is also present on the initialization declaration, even if it is in some other TU etc. There is a small problem though, we use the tls wrappers not just if the thread_local variable needs dynamic initialization, but also when it has static initialization, but non-trivial destructor, as the "dynamic initialization" in that case needs to register the destructor. So, the following patch optimizes constinit thread_local vars only if we can prove they will not have non-trivial destructors. That includes the case where we have incomplete type where we don't know and need to conservatively assume the type will have non-trivial destructor at the initializing declaration side. 2021-08-11 Jakub Jelinek PR c++/101786 * decl2.c (var_defined_without_dynamic_init): Return true for DECL_DECLARED_CONSTINIT_P with complete type and trivial destructor. * g++.dg/cpp2a/constinit16.C: New test. --- gcc/cp/decl2.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 9564b0d..ba27388 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -3447,6 +3447,12 @@ set_guard (tree guard) static bool var_defined_without_dynamic_init (tree var) { + /* constinit vars are guaranteed to not have dynamic initializer, + but still registering the destructor counts as dynamic initialization. */ + if (DECL_DECLARED_CONSTINIT_P (var) + && COMPLETE_TYPE_P (TREE_TYPE (var)) + && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (var))) + return true; /* If it's defined in another TU, we can't tell. */ if (DECL_EXTERNAL (var)) return false; -- cgit v1.1 From 9707d2e5dbb92d2bc990c922461a5a16ae652319 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 11 Aug 2021 16:53:53 -0400 Subject: c++: parameterized requires-expr as default argument [PR101725] Here we're rejecting the default template argument requires (T t) { x(t); } because we consider the 't' in the requirement to be a local variable (according to local_variable_p), and we generally forbid local variables from appearing inside default arguments. We can perhaps fix this by giving special treatment to parameters introduced by requires-expressions, but DR 2082 relaxed the restriction about local variables appearing within default arguments to permit them inside unevaluated operands thereof. So this patch just implements DR 2082 which also fixes this PR since a requires-expression is an unevaluated context. PR c++/101725 DR 2082 gcc/cp/ChangeLog: * cp-tree.h (unevaluated_p): Return true for REQUIRES_EXPR. * decl.c (local_variable_p_walkfn): Don't walk into unevaluated operands. * parser.c (cp_parser_primary_expression) : Never reject uses of local variables in unevaluated contexts. * tree.c (cp_walk_subtrees) : Increment cp_unevaluated_operand. Use cp_walk_tree directly instead of WALK_SUBTREE to avoid the goto. Use REQUIRES_EXPR_REQS instead of TREE_OPERAND directly. gcc/testsuite/ChangeLog: * g++.dg/DRs/dr2082.C: New test. * g++.dg/cpp2a/concepts-uneval4.C: New test. --- gcc/cp/cp-tree.h | 3 ++- gcc/cp/decl.c | 8 ++++++++ gcc/cp/parser.c | 5 ++++- gcc/cp/tree.c | 4 +++- 4 files changed, 17 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9a47a87..6a8264b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8494,7 +8494,8 @@ unevaluated_p (tree_code code) return (code == DECLTYPE_TYPE || code == ALIGNOF_EXPR || code == SIZEOF_EXPR - || code == NOEXCEPT_EXPR); + || code == NOEXCEPT_EXPR + || code == REQUIRES_EXPR); } /* RAII class to push/pop the access scope for T. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index f626f1e..b3671ee 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -14270,6 +14270,14 @@ static tree local_variable_p_walkfn (tree *tp, int *walk_subtrees, void * /*data*/) { + if (unevaluated_p (TREE_CODE (*tp))) + { + /* DR 2082 permits local variables in unevaluated contexts + within a default argument. */ + *walk_subtrees = 0; + return NULL_TREE; + } + if (local_variable_p (*tp) && (!DECL_ARTIFICIAL (*tp) || DECL_NAME (*tp) == this_identifier)) return *tp; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b5e117d..d564e3b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -5989,7 +5989,10 @@ cp_parser_primary_expression (cp_parser *parser, /* Check to see if DECL is a local variable in a context where that is forbidden. */ if ((parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN) - && local_variable_p (decl)) + && local_variable_p (decl) + /* DR 2082 permits local variables in unevaluated contexts + within a default argument. */ + && !cp_unevaluated_operand) { const char *msg = (TREE_CODE (decl) == PARM_DECL diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8345396..e8831b2 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -5386,7 +5386,9 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, // walk the parameter list. Doing so causes false // positives in the pack expansion checker since the // requires parameters are introduced as pack expansions. - WALK_SUBTREE (TREE_OPERAND (*tp, 1)); + ++cp_unevaluated_operand; + result = cp_walk_tree (&REQUIRES_EXPR_REQS (*tp), func, data, pset); + --cp_unevaluated_operand; *walk_subtrees_p = 0; break; -- cgit v1.1 From 58f87503427e27bb069bd1841100f3c53440d51a Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 12 Aug 2021 00:16:28 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fbd4af2e..fd4aa6e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,40 @@ +2021-08-11 Patrick Palka + + PR c++/101725 + DR 2082 + * cp-tree.h (unevaluated_p): Return true for REQUIRES_EXPR. + * decl.c (local_variable_p_walkfn): Don't walk into unevaluated + operands. + * parser.c (cp_parser_primary_expression) : Never + reject uses of local variables in unevaluated contexts. + * tree.c (cp_walk_subtrees) : Increment + cp_unevaluated_operand. Use cp_walk_tree directly instead of + WALK_SUBTREE to avoid the goto. Use REQUIRES_EXPR_REQS instead + of TREE_OPERAND directly. + +2021-08-11 Jakub Jelinek + + PR c++/101786 + * decl2.c (var_defined_without_dynamic_init): Return true for + DECL_DECLARED_CONSTINIT_P with complete type and trivial destructor. + +2021-08-11 Patrick Palka + + PR c++/79501 + * parser.c (maybe_adjust_declarator_for_dguide): New, split + out from ... + (cp_parser_init_declarator): ... here. + (cp_parser_member_declaration): Use it. + +2021-08-11 Patrick Palka + + PR c++/89062 + * parser.c (cp_parser_parameter_declaration_list): Don't call + grokdeclarator if cp_parser_error_occurred. + (cp_parser_parameter_declaration): Simulate an error if we see + the beginning of a CTAD form, i.e. if we see an opening brace + after the decl-specifier-seq and the type is a CTAD placeholder. + 2021-08-10 Jakub Jelinek * parser.c (cp_parser_member_declaration): Move odsd declaration -- cgit v1.1 From 21fd62e5ca9967bba8f97fd6244a8c6a564c2146 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 11 Aug 2021 20:59:53 -0400 Subject: c++: constexpr std::construct_at on empty field [PR101663] Here during constexpr evaluation of std::construct_at(&a._M_value) we find ourselves in cxx_eval_store_expression where the target object is 'a._M_value' and the initializer is {}. Since _M_value is an empty [[no_unique_address]] member we don't create a sub-CONSTRUCTOR for it, so we end up in the early exit code path for empty stores with mismatched types and trip over the assert therein gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval); because lval is true. The reason it's true is because the INIT_EXPR in question is the LHS of a COMPOUND_EXPR, and evaluation of the LHS is always performed with lval=true (to indicate there's no lvalue-to-rvalue conversion). This patch makes the code path in question handle the lval=true case appropriately rather than asserting. In passing, it also consolidates the duplicate implementations of std::construct_at/destroy_at in some of the C++20 constexpr tests into a common header file. PR c++/101663 gcc/cp/ChangeLog: * constexpr.c (cxx_eval_store_expression): Handle the lval=true case in the early exit code path for empty stores with mismatched types. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/construct_at.h: New convenience header file that defines minimal implementations of std::construct_at/destroy_at, split out from ... * g++.dg/cpp2a/constexpr-new5.C: ... here. * g++.dg/cpp2a/constexpr-new6.C: Use the header. * g++.dg/cpp2a/constexpr-new14.C: Likewise. * g++.dg/cpp2a/constexpr-new20.C: New test. --- gcc/cp/constexpr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 1af365d..25d84a3 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5588,8 +5588,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, argument, which has the derived type rather than the base type. In this situation, just evaluate the initializer and return, since there's no actual data to store. */ - gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval); - return init; + gcc_assert (is_empty_class (TREE_TYPE (init))); + return lval ? target : init; } CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init); TREE_CONSTANT (*valp) = TREE_CONSTANT (init); -- cgit v1.1 From 3890c28ac5bd03ba334a20fbf9518a37dcdbfe5d Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 09:09:39 +0200 Subject: c++: Fix up parsing of attributes for using-directive As I've said earlier and added xfails in gen-attrs-76.C test, https://eel.is/c++draft/namespace.udir#nt:using-directive has attribute-specifier-seq[opt] at the start, not at the end before ; as gcc is expecting. IMHO we should continue parsing at the end the GNU attributes because using namespace N __attribute__((strong));, while not supported anymore, used to be supported in the past, but my code searches for using namespace N [[gnu::strong]]; didn't reveal anything at all. 2021-08-12 Jakub Jelinek * parser.c (cp_parser_block_declaration): Call cp_parser_using_directive for C++11 attributes followed by using namespace tokens. (cp_parser_using_directive): Parse C++11 attributes at the start of the directive rather than at the end, only parse GNU attributes at the end. * g++.dg/lookup/strong-using.C: Add test using [[gnu::strong]] as well. * g++.dg/lookup/strong-using2.C: Likewise. * g++.dg/cpp0x/gen-attrs-58.C: Move alignas(int) before using namespace. * g++.dg/cpp0x/gen-attrs-59.C: Move alignas(X) before using namespace, add tests for alignas before semicolon. * g++.dg/cpp0x/gen-attrs-76.C: Remove xfails. Add test for C++11 attributes on using directive before semicolon. --- gcc/cp/parser.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d564e3b..ec885d7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -14853,6 +14853,7 @@ cp_parser_block_declaration (cp_parser *parser, /* Peek at the next token to figure out which kind of declaration is present. */ cp_token *token1 = cp_lexer_peek_token (parser->lexer); + size_t attr_idx; /* If the next keyword is `asm', we have an asm-definition. */ if (token1->keyword == RID_ASM) @@ -14906,6 +14907,18 @@ cp_parser_block_declaration (cp_parser *parser, /* If the next token is `static_assert' we have a static assertion. */ else if (token1->keyword == RID_STATIC_ASSERT) cp_parser_static_assert (parser, /*member_p=*/false); + /* If the next tokens after attributes is `using namespace', then we have + a using-directive. */ + else if ((attr_idx = cp_parser_skip_std_attribute_spec_seq (parser, 1)) != 1 + && cp_lexer_nth_token_is_keyword (parser->lexer, attr_idx, + RID_USING) + && cp_lexer_nth_token_is_keyword (parser->lexer, attr_idx + 1, + RID_NAMESPACE)) + { + if (statement_p) + cp_parser_commit_to_tentative_parse (parser); + cp_parser_using_directive (parser); + } /* Anything else must be a simple-declaration. */ else cp_parser_simple_declaration (parser, !statement_p, @@ -21609,14 +21622,21 @@ cp_parser_alias_declaration (cp_parser* parser) /* Parse a using-directive. using-directive: - using namespace :: [opt] nested-name-specifier [opt] - namespace-name ; */ + attribute-specifier-seq [opt] using namespace :: [opt] + nested-name-specifier [opt] namespace-name ; */ static void cp_parser_using_directive (cp_parser* parser) { tree namespace_decl; - tree attribs; + tree attribs = cp_parser_std_attribute_spec_seq (parser); + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + /* Error during attribute parsing that resulted in skipping + to next semicolon. */ + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + return; + } /* Look for the `using' keyword. */ cp_parser_require_keyword (parser, RID_USING, RT_USING); @@ -21633,8 +21653,9 @@ cp_parser_using_directive (cp_parser* parser) /* Get the namespace being used. */ namespace_decl = cp_parser_namespace_name (parser); cp_warn_deprecated_use_scopes (namespace_decl); - /* And any specified attributes. */ - attribs = cp_parser_attributes_opt (parser); + /* And any specified GNU attributes. */ + if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + attribs = chainon (attribs, cp_parser_gnu_attributes_opt (parser)); /* Update the symbol table. */ finish_using_directive (namespace_decl, attribs); -- cgit v1.1 From c84f79e9e3f63e9ae447fd15dbd0a768cab3f643 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 09:10:46 +0200 Subject: openmp: Diagnose omp::directive/sequence on using-directive With the using-directive parsing changes, we now emit only a warning for [[omp::directive (...)]] on using-directive. While that is right without -fopenmp/-fopenmp-simd, when OpenMP is enabled, that should be an error as OpenMP (is going to) disallow such attributes there as they do not appertain to a statement. 2021-08-12 Jakub Jelinek * name-lookup.c (finish_using_directive): Diagnose omp::directive or omp::sequence attributes on using-directive. * g++.dg/gomp/attrs-11.C: Adjust expected diagnostics. --- gcc/cp/name-lookup.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 1be5f3d..8e9c61e 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -8560,6 +8560,7 @@ finish_using_directive (tree target, tree attribs) add_using_namespace (current_binding_level->using_directives, ORIGINAL_NAMESPACE (target)); + bool diagnosed = false; if (attribs != error_mark_node) for (tree a = attribs; a; a = TREE_CHAIN (a)) { @@ -8572,6 +8573,16 @@ finish_using_directive (tree target, tree attribs) inform (DECL_SOURCE_LOCATION (target), "you can use an inline namespace instead"); } + else if ((flag_openmp || flag_openmp_simd) + && get_attribute_namespace (a) == omp_identifier + && (is_attribute_p ("directive", name) + || is_attribute_p ("sequence", name))) + { + if (!diagnosed) + error ("% not allowed to be specified in this " + "context", name); + diagnosed = true; + } else warning (OPT_Wattributes, "%qD attribute directive ignored", name); } -- cgit v1.1 From 9b7ab853bf33106fd0539e36d6ce7730269026e1 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 09:16:13 +0200 Subject: c++: Fix ICE on defaulted spaceship with pointer return type [PR94162] The spaceship-synth-neg6.C testcase ICEs because we call cat_tag_for on the explicit return type, but pointer types don't have TYPE_LINKAGE_IDENTIFIER. The patch fixes that by checking for CLASS_TYPE_P only and also adds verification that it is in std namespace, so we don't return non-cc_last for my_namespace::partial_ordering. The g++.dg/cpp2a/spaceship-synth11.C testcase is from a PR that has been fixed with r12-619-gfc178519771db508c03611cff4a1466cf67fce1d (but not backported to 11). 2021-08-12 Jakub Jelinek gcc/cp/ PR c++/94162 * method.c (cat_tag_for): Return cc_last for !CLASS_TYPE_P or for classes not in std namespace. gcc/testsuite/ PR c++/99429 * g++.dg/cpp2a/spaceship-synth11.C: New test. PR c++/94162 * g++.dg/cpp2a/spaceship-synth-neg6.C: New test. --- gcc/cp/method.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/method.c b/gcc/cp/method.c index f268aab..353046d 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1029,6 +1029,8 @@ is_cat (tree type, comp_cat_tag tag) static comp_cat_tag cat_tag_for (tree type) { + if (!CLASS_TYPE_P (type) || !decl_in_std_namespace_p (TYPE_MAIN_DECL (type))) + return cc_last; for (int i = 0; i < cc_last; ++i) { comp_cat_tag tag = (comp_cat_tag)i; -- cgit v1.1 From ef07b918a7ad4f64e0e1e3db21d861f2e79de92a Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 09:18:23 +0200 Subject: openmp: Diagnose another case of mixing parameter and attribute syntax This patch diagnoses cases like: #pragma omp parallel [[omp::directive (declare simd)]] int foo (); or #pragma omp taskgroup int bar [[omp::directive (declare simd)]] (int); where the pragma is on the same declaration statement as the declare simd attribute. 2021-08-12 Jakub Jelinek * parser.c (cp_parser_lambda_body): Add temp overrides for parser->{omp_declare_simd,oacc_routine,omp_attrs_forbidden_p}. (cp_parser_statement): Restore parser->omp_attrs_forbidden_p for cp_parser_declaration_statement. (cp_parser_default_argument): Add temp override for parser->omp_attrs_forbidden_p. (cp_parser_late_parsing_omp_declare_simd): Diagnose declare simd or declare variant in attribute syntax on a declaration immediately following an OpenMP construct in pragma syntax. * g++.dg/gomp/attrs-11.C: Add new tests. --- gcc/cp/parser.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ec885d7..fbb8130 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11628,6 +11628,9 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) middle of an expression. */ ++function_depth; + auto odsd = make_temp_override (parser->omp_declare_simd, NULL); + auto ord = make_temp_override (parser->oacc_routine, NULL); + auto oafp = make_temp_override (parser->omp_attrs_forbidden_p, false); vec omp_privatization_save; save_omp_privatization_clauses (omp_privatization_save); /* Clear this in case we're in the middle of a default argument. */ @@ -12271,9 +12274,11 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, so let's un-parse them. */ saved_tokens.rollback(); + parser->omp_attrs_forbidden_p = omp_attrs_forbidden_p; cp_parser_parse_tentatively (parser); /* Try to parse the declaration-statement. */ cp_parser_declaration_statement (parser); + parser->omp_attrs_forbidden_p = false; /* If that worked, we're done. */ if (cp_parser_parse_definitely (parser)) return; @@ -24768,6 +24773,8 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p) parser->greater_than_is_operator_p = !template_parm_p; auto odsd = make_temp_override (parser->omp_declare_simd, NULL); auto ord = make_temp_override (parser->oacc_routine, NULL); + auto oafp = make_temp_override (parser->omp_attrs_forbidden_p, false); + /* Local variable names (and the `this' keyword) may not appear in a default argument. */ saved_local_variables_forbidden_p = parser->local_variables_forbidden_p; @@ -44503,6 +44510,14 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) continue; } + if (parser->omp_attrs_forbidden_p) + { + error_at (first->location, + "mixing OpenMP directives with attribute and " + "pragma syntax on the same statement"); + parser->omp_attrs_forbidden_p = false; + } + if (!flag_openmp && strcmp (directive[1], "simd") != 0) continue; if (lexer == NULL) -- 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/cp-tree.h | 8 +++++--- gcc/cp/decl2.c | 2 +- gcc/cp/parser.c | 23 ++++++++++++++++++++--- gcc/cp/semantics.c | 4 ++-- 4 files changed, 28 insertions(+), 9 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6a8264b..bd3f12a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1789,6 +1789,10 @@ union GTY((desc ("cp_tree_node_structure (&%h)"), }; +struct GTY(()) omp_declare_target_attr { + bool attr_syntax; +}; + /* Global state. */ struct GTY(()) saved_scope { @@ -1826,9 +1830,6 @@ struct GTY(()) saved_scope { int unevaluated_operand; int inhibit_evaluation_warnings; int noexcept_operand; - /* If non-zero, implicit "omp declare target" attribute is added into the - attribute lists. */ - int omp_declare_target_attribute; int ref_temp_count; struct stmt_tree_s x_stmt_tree; @@ -1837,6 +1838,7 @@ struct GTY(()) saved_scope { cp_binding_level *bindings; hash_map *GTY((skip)) x_local_specializations; + vec *omp_declare_target_attribute; struct saved_scope *prev; }; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index ba27388..0c9d2f4 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1551,7 +1551,7 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) return; /* Add implicit "omp declare target" attribute if requested. */ - if (scope_chain->omp_declare_target_attribute + if (vec_safe_length (scope_chain->omp_declare_target_attribute) && ((VAR_P (*decl) && (TREE_STATIC (*decl) || DECL_EXTERNAL (*decl))) || TREE_CODE (*decl) == FUNCTION_DECL)) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index fbb8130..74de529 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -44641,8 +44641,10 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) } else { + struct omp_declare_target_attr a + = { parser->lexer->in_omp_attribute_pragma }; + vec_safe_push (scope_chain->omp_declare_target_attribute, a); cp_parser_require_pragma_eol (parser, pragma_tok); - scope_chain->omp_declare_target_attribute++; return; } for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) @@ -44723,6 +44725,7 @@ static void cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) { const char *p = ""; + bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -44753,12 +44756,26 @@ cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) return; } cp_parser_require_pragma_eol (parser, pragma_tok); - if (!scope_chain->omp_declare_target_attribute) + if (!vec_safe_length (scope_chain->omp_declare_target_attribute)) error_at (pragma_tok->location, "%<#pragma omp end declare target%> without corresponding " "%<#pragma omp declare target%>"); else - scope_chain->omp_declare_target_attribute--; + { + omp_declare_target_attr + a = scope_chain->omp_declare_target_attribute->pop (); + if (a.attr_syntax != in_omp_attribute_pragma) + { + if (a.attr_syntax) + error_at (pragma_tok->location, + "% in attribute syntax terminated " + "with % in pragma syntax"); + else + error_at (pragma_tok->location, + "% in pragma syntax terminated " + "with % in attribute syntax"); + } + } } /* Helper function of cp_parser_omp_declare_reduction. Parse the combiner 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 432de08498142d2266c0fb05f2c555a7f1e10ddd Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Thu, 12 Aug 2021 15:48:28 +0200 Subject: OpenMP 5.1: Add proc-bind 'primary' support In OpenMP 5.1 "master thread" was changed to "primary thread" and the proc_bind clause and the OMP_PROC_BIND environment variable now take 'primary' as argument as alias for 'master', while the latter is deprecated. This commit accepts 'primary' and adds the named constant omp_proc_bind_primary and changes 'master thread' in the documentation; however, given that not even OpenMP 5.0 is fully supported, omp_display_env and the dumps currently still output 'master' and there is no deprecation warning when using the 'master' in the proc_bind clause. gcc/c/ChangeLog: * c-parser.c (c_parser_omp_clause_proc_bind): Accept 'primary' as alias for 'master'. gcc/cp/ChangeLog: * parser.c (cp_parser_omp_clause_proc_bind): Accept 'primary' as alias for 'master'. gcc/fortran/ChangeLog: * gfortran.h (gfc_omp_proc_bind_kind): Add OMP_PROC_BIND_PRIMARY. * dump-parse-tree.c (show_omp_clauses): Add TODO comment to change 'master' to 'primary' in proc_bind for OpenMP 5.1. * intrinsic.texi (OMP_LIB): Mention OpenMP 5.1; add omp_proc_bind_primary. * openmp.c (gfc_match_omp_clauses): Accept 'primary' as alias for 'master'. * trans-openmp.c (gfc_trans_omp_clauses): Handle OMP_PROC_BIND_PRIMARY. gcc/ChangeLog: * tree-core.h (omp_clause_proc_bind_kind): Add OMP_CLAUSE_PROC_BIND_PRIMARY. * tree-pretty-print.c (dump_omp_clause): Add TODO comment to change 'master' to 'primary' in proc_bind for OpenMP 5.1. libgomp/ChangeLog: * env.c (parse_bind_var): Accept 'primary' as alias for 'master'. (omp_display_env): Add TODO comment to change 'master' to 'primary' in proc_bind for OpenMP 5.1. * libgomp.texi: Change 'master thread' to 'primary thread' in line with OpenMP 5.1. (omp_get_proc_bind): Add omp_proc_bind_primary and note that omp_proc_bind_master is an alias of it. (OMP_PROC_BIND): Mention 'PRIMARY'. * omp.h.in (__GOMP_DEPRECATED_5_1): Define. (omp_proc_bind_primary): Add. (omp_proc_bind_master): Deprecate for OpenMP 5.1. * omp_lib.f90.in (omp_proc_bind_primary): Add. (omp_proc_bind_master): Deprecate for OpenMP 5.1. * omp_lib.h.in (omp_proc_bind_primary): Add. * testsuite/libgomp.c/affinity-1.c: Check that 'primary' works and is identical to 'master'. gcc/testsuite/ChangeLog: * c-c++-common/gomp/pr61486-2.c: Duplicate one proc_bind(master) testcase and test proc_bind(primary) instead. * gfortran.dg/gomp/affinity-1.f90: Likewise. --- gcc/cp/parser.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 74de529..b7fe4b4 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -39020,7 +39020,8 @@ cp_parser_omp_clause_dist_schedule (cp_parser *parser, tree list, proc_bind ( proc-bind-kind ) proc-bind-kind: - master | close | spread */ + primary | master | close | spread + where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */ static tree cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, @@ -39037,7 +39038,9 @@ cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); - if (strcmp ("master", p) == 0) + if (strcmp ("primary", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_PRIMARY; + else if (strcmp ("master", p) == 0) kind = OMP_CLAUSE_PROC_BIND_MASTER; else if (strcmp ("close", p) == 0) kind = OMP_CLAUSE_PROC_BIND_CLOSE; -- cgit v1.1 From 27a1fb385b7fe706f05608e53f3e91d7d3442b8b Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Fri, 6 Aug 2021 16:14:16 +0100 Subject: c++: fix ptrmemfunc template instantiation [PR101219] r12-1804 ("cp: add support for per-location warning groups.") among other things removed warning suppression from a few places including ptrmemfuncs. This exposed a bug in warning detection code as a reference to missing BINFO (it's intentionally missing for ptrmemfunc types): crash_signal gcc/toplev.c:328 perform_or_defer_access_check(tree_node*, tree_node*, tree_node*, int, access_failure_info*) gcc/cp/semantics.c:490 finish_non_static_data_member(tree_node*, tree_node*, tree_node*) gcc/cp/semantics.c:2208 ... The change special cases ptrmemfuncs in templace substitution by using build_ptrmemfunc_access_expr() instead of finish_non_static_data_member(). gcc/cp/ChangeLog: PR c++/101219 * pt.c (tsubst_copy_and_build): Use build_ptrmemfunc_access_expr to construct ptrmemfunc expression instantiation. gcc/testsuite/ChangeLog: PR c++/101219 * g++.dg/warn/pr101219.C: New test. --- gcc/cp/pt.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b396ddd..42ea51c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20530,7 +20530,13 @@ tsubst_copy_and_build (tree t, if (member == error_mark_node) RETURN (error_mark_node); - if (TREE_CODE (member) == FIELD_DECL) + if (object_type && TYPE_PTRMEMFUNC_P (object_type) + && TREE_CODE (member) == FIELD_DECL) + { + r = build_ptrmemfunc_access_expr (object, DECL_NAME (member)); + RETURN (r); + } + else if (TREE_CODE (member) == FIELD_DECL) { r = finish_non_static_data_member (member, object, NULL_TREE); if (TREE_CODE (r) == COMPONENT_REF) -- 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/parser.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++- gcc/cp/pt.c | 2 + gcc/cp/semantics.c | 23 +++++++++ 3 files changed, 165 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b7fe4b4..edb69ae 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -36004,7 +36004,9 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; break; case 'f': - if (!strcmp ("final", p)) + if (!strcmp ("filter", p)) + result = PRAGMA_OMP_CLAUSE_FILTER; + else if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("finalize", p)) result = PRAGMA_OACC_CLAUSE_FINALIZE; @@ -37340,6 +37342,34 @@ cp_parser_omp_clause_hint (cp_parser *parser, tree list, location_t location) return c; } +/* OpenMP 5.1: + filter ( integer-expression ) */ + +static tree +cp_parser_omp_clause_filter (cp_parser *parser, tree list, location_t location) +{ + tree t, c; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + t = cp_parser_assignment_expression (parser); + + if (t == error_mark_node + || !parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + check_no_duplicate_clause (list, OMP_CLAUSE_FILTER, "filter", location); + + c = build_omp_clause (location, OMP_CLAUSE_FILTER); + OMP_CLAUSE_FILTER_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + /* OpenMP 4.5: defaultmap ( tofrom : scalar ) @@ -39449,6 +39479,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, token->location, false); c_name = "default"; break; + case PRAGMA_OMP_CLAUSE_FILTER: + clauses = cp_parser_omp_clause_filter (parser, clauses, + token->location); + c_name = "filter"; + break; case PRAGMA_OMP_CLAUSE_FINAL: clauses = cp_parser_omp_clause_final (parser, clauses, token->location); c_name = "final"; @@ -41985,6 +42020,73 @@ cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok, cp_parser_omp_structured_block (parser, if_p)); } +/* OpenMP 5.1: + # pragma omp masked masked-clauses new-line + structured-block */ + +#define OMP_MASKED_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER) + +static tree +cp_parser_omp_masked (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " masked"); + mask |= OMP_MASKED_CLAUSE_MASK; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "taskloop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + if (!flag_openmp) /* flag_openmp_simd */ + return cp_parser_omp_taskloop (parser, pragma_tok, p_name, mask, + cclauses, if_p); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + ret = cp_parser_omp_taskloop (parser, pragma_tok, p_name, mask, + cclauses, if_p); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + ret = c_finish_omp_masked (loc, body, + cclauses[C_OMP_CLAUSE_SPLIT_MASKED]); + OMP_MASKED_COMBINED (ret) = 1; + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_MASTER, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED]; + } + + return c_finish_omp_masked (loc, + cp_parser_omp_structured_block (parser, if_p), + clauses); +} + /* OpenMP 2.5: # pragma omp ordered new-line structured-block @@ -42238,7 +42340,37 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, { tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); - if (cclauses == NULL && strcmp (p, "master") == 0) + if (cclauses == NULL && strcmp (p, "masked") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + if (!flag_openmp) /* flag_openmp_simd */ + return cp_parser_omp_masked (parser, pragma_tok, p_name, mask, + cclauses, if_p); + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + tree ret = cp_parser_omp_masked (parser, pragma_tok, p_name, mask, + cclauses, if_p); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + if (ret == NULL_TREE) + return ret; + /* masked does have just filter clause, but during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel masked + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel masked taskloop simd lastprivate (x) */ + if (OMP_MASKED_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses == NULL && strcmp (p, "master") == 0) { tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; cclauses = cclauses_buf; @@ -45824,6 +45956,11 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) stmt = cp_parser_omp_loop (parser, pragma_tok, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_MASKED: + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_masked (parser, pragma_tok, p_name, mask, NULL, + if_p); + break; case PRAGMA_OMP_MASTER: strcpy (p_name, "#pragma omp"); stmt = cp_parser_omp_master (parser, pragma_tok, p_name, mask, NULL, @@ -46464,6 +46601,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case PRAGMA_OMP_DISTRIBUTE: case PRAGMA_OMP_FOR: case PRAGMA_OMP_LOOP: + case PRAGMA_OMP_MASKED: case PRAGMA_OMP_MASTER: case PRAGMA_OMP_PARALLEL: case PRAGMA_OMP_SECTIONS: diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 42ea51c..0870ccd 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17394,6 +17394,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, case OMP_CLAUSE_PRIORITY: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_NUM_GANGS: case OMP_CLAUSE_NUM_WORKERS: case OMP_CLAUSE_VECTOR_LENGTH: @@ -18786,6 +18787,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_SECTIONS: + case OMP_MASKED: omp_parallel_combined_clauses = NULL; /* FALLTHRU */ case OMP_SINGLE: 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 72be20e20299ec57b4bc9ba03d5b7d6bf10e97cc Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 13 Aug 2021 00:16:43 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fd4aa6e..7a4a707 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,84 @@ +2021-08-12 Jakub Jelinek + + * 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. + +2021-08-12 Sergei Trofimovich + + PR c++/101219 + * pt.c (tsubst_copy_and_build): Use build_ptrmemfunc_access_expr + to construct ptrmemfunc expression instantiation. + +2021-08-12 Tobias Burnus + + * parser.c (cp_parser_omp_clause_proc_bind): Accept + 'primary' as alias for 'master'. + +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. + +2021-08-12 Jakub Jelinek + + * parser.c (cp_parser_lambda_body): Add temp overrides + for parser->{omp_declare_simd,oacc_routine,omp_attrs_forbidden_p}. + (cp_parser_statement): Restore parser->omp_attrs_forbidden_p for + cp_parser_declaration_statement. + (cp_parser_default_argument): Add temp override for + parser->omp_attrs_forbidden_p. + (cp_parser_late_parsing_omp_declare_simd): Diagnose declare simd + or declare variant in attribute syntax on a declaration immediately + following an OpenMP construct in pragma syntax. + +2021-08-12 Jakub Jelinek + + PR c++/94162 + * method.c (cat_tag_for): Return cc_last for !CLASS_TYPE_P + or for classes not in std namespace. + +2021-08-12 Jakub Jelinek + + * name-lookup.c (finish_using_directive): Diagnose omp::directive + or omp::sequence attributes on using-directive. + +2021-08-12 Jakub Jelinek + + * parser.c (cp_parser_block_declaration): Call + cp_parser_using_directive for C++11 attributes followed by + using namespace tokens. + (cp_parser_using_directive): Parse C++11 attributes at the start + of the directive rather than at the end, only parse GNU attributes + at the end. + +2021-08-12 Patrick Palka + + PR c++/101663 + * constexpr.c (cxx_eval_store_expression): Handle the lval=true + case in the early exit code path for empty stores with mismatched + types. + 2021-08-11 Patrick Palka PR c++/101725 -- cgit v1.1 From e45483c7c4badc4bf2d6ced22360ce1ab172967f Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 17 Aug 2021 09:30:09 +0200 Subject: openmp: Implement OpenMP 5.1 scope construct This patch implements the OpenMP 5.1 scope construct, which is similar to worksharing constructs in many regards, but isn't one of them. The body of the construct is encountered by all threads though, it can be nested in itself or intermixed with taskgroup and worksharing etc. constructs can appear inside of it (but it can't be nested in worksharing etc. constructs). The main purpose of the construct is to allow reductions (normal and task ones) without the need to close the parallel and reopen another one. If it doesn't have task reductions, it can be implemented without any new library support, with nowait it just does the privatizations at the start if any and reductions before the end of the body, with without nowait emits a normal GOMP_barrier{,_cancel} at the end too. For task reductions, we need to ensure only one thread initializes the task reduction library data structures and other threads copy from that, so a new GOMP_scope_start routine is added to the library for that. It acts as if the start of the scope construct is a nowait worksharing construct (that is ok, it can't be nested in other worksharing constructs and all threads need to encounter the start in the same order) which does the task reduction initialization, but as the body can have other scope constructs and/or worksharing constructs, that is all where we use this dummy worksharing construct. With task reductions, the construct must not have nowait and ends with a GOMP_barrier{,_cancel}, followed by task reductions followed by GOMP_workshare_task_reduction_unregister. Only C/C++ FE support is done. 2021-08-17 Jakub Jelinek gcc/ * tree.def (OMP_SCOPE): New tree code. * tree.h (OMP_SCOPE_BODY, OMP_SCOPE_CLAUSES): Define. * tree-nested.c (convert_nonlocal_reference_stmt, convert_local_reference_stmt, convert_gimple_call): Handle GIMPLE_OMP_SCOPE. * tree-pretty-print.c (dump_generic_node): Handle OMP_SCOPE. * gimple.def (GIMPLE_OMP_SCOPE): New gimple code. * gimple.c (gimple_build_omp_scope): New function. (gimple_copy): Handle GIMPLE_OMP_SCOPE. * gimple.h (gimple_build_omp_scope): Declare. (gimple_has_substatements): Handle GIMPLE_OMP_SCOPE. (gimple_omp_scope_clauses, gimple_omp_scope_clauses_ptr, gimple_omp_scope_set_clauses): New inline functions. (CASE_GIMPLE_OMP): Add GIMPLE_OMP_SCOPE. * gimple-pretty-print.c (dump_gimple_omp_scope): New function. (pp_gimple_stmt_1): Handle GIMPLE_OMP_SCOPE. * 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): For task reductions, handle OMP_SCOPE like ORT_WORKSHARE constructs. Adjust diagnostics for % allowing task reductions. Reject inscan reductions on scope. (omp_find_stores_stmt): Handle GIMPLE_OMP_SCOPE. (gimplify_omp_workshare, gimplify_expr): Handle OMP_SCOPE. * tree-inline.c (remap_gimple_stmt): Handle GIMPLE_OMP_SCOPE. (estimate_num_insns): Likewise. * omp-low.c (build_outer_var_ref): Look through GIMPLE_OMP_SCOPE contexts if var isn't privatized there. (check_omp_nesting_restrictions): Handle GIMPLE_OMP_SCOPE. (scan_omp_1_stmt): Likewise. (maybe_add_implicit_barrier_cancel): Look through outer scope constructs. (lower_omp_scope): New function. (lower_omp_task_reductions): Handle OMP_SCOPE. (lower_omp_1): Handle GIMPLE_OMP_SCOPE. (diagnose_sb_1, diagnose_sb_2): Likewise. * omp-expand.c (expand_omp_single): Support also GIMPLE_OMP_SCOPE. (expand_omp): Handle GIMPLE_OMP_SCOPE. (omp_make_gimple_edges): Likewise. * omp-builtins.def (BUILT_IN_GOMP_SCOPE_START): New built-in. gcc/c-family/ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_SCOPE. * c-pragma.c (omp_pragmas): Add scope construct. * c-omp.c (omp_directives): Uncomment scope directive entry. gcc/c/ * c-parser.c (OMP_SCOPE_CLAUSE_MASK): Define. (c_parser_omp_scope): New function. (c_parser_omp_construct): Handle PRAGMA_OMP_SCOPE. gcc/cp/ * parser.c (OMP_SCOPE_CLAUSE_MASK): Define. (cp_parser_omp_scope): New function. (cp_parser_omp_construct, cp_parser_pragma): Handle PRAGMA_OMP_SCOPE. * pt.c (tsubst_expr): Handle OMP_SCOPE. gcc/testsuite/ * c-c++-common/gomp/nesting-2.c (foo): Add scope and masked construct tests. * c-c++-common/gomp/scan-1.c (f3): Add scope construct test.. * c-c++-common/gomp/cancel-1.c (f2): Add scope and masked construct tests. * c-c++-common/gomp/reduction-task-2.c (bar): Add scope construct test. Adjust diagnostics for the addition of scope. * c-c++-common/gomp/loop-1.c (f5): Add master, masked and scope construct tests. * c-c++-common/gomp/clause-dups-1.c (f1): Add scope construct test. * gcc.dg/gomp/nesting-1.c (f1, f2, f3): Add scope construct tests. * c-c++-common/gomp/scope-1.c: New test. * c-c++-common/gomp/scope-2.c: New test. * g++.dg/gomp/attrs-1.C (bar): Add scope construct tests. * g++.dg/gomp/attrs-2.C (bar): Likewise. * gfortran.dg/gomp/reduction4.f90: Adjust expected diagnostics. * gfortran.dg/gomp/reduction7.f90: Likewise. libgomp/ * Makefile.am (libgomp_la_SOURCES): Add scope.c * Makefile.in: Regenerated. * libgomp_g.h (GOMP_scope_start): Declare. * libgomp.map: Add GOMP_scope_start@@GOMP_5.1. * scope.c: New file. * testsuite/libgomp.c-c++-common/scope-1.c: New test. * testsuite/libgomp.c-c++-common/task-reduction-16.c: New test. --- gcc/cp/parser.c | 28 ++++++++++++++++++++++++++++ gcc/cp/pt.c | 1 + 2 files changed, 29 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index edb69ae..c31965a 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -42492,6 +42492,30 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok, bool *if_p) return add_stmt (stmt); } +/* OpenMP 5.1: + # pragma omp scope scope-clause[optseq] new-line + structured-block */ + +#define OMP_SCOPE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +cp_parser_omp_scope (cp_parser *parser, cp_token *pragma_tok, bool *if_p) +{ + tree stmt = make_node (OMP_SCOPE); + TREE_TYPE (stmt) = void_type_node; + SET_EXPR_LOCATION (stmt, pragma_tok->location); + + OMP_SCOPE_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK, + "#pragma omp scope", pragma_tok); + OMP_SCOPE_BODY (stmt) = cp_parser_omp_structured_block (parser, if_p); + + return add_stmt (stmt); +} + /* OpenMP 3.0: # pragma omp task task-clause[optseq] new-line structured-block */ @@ -45971,6 +45995,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) stmt = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_SCOPE: + stmt = cp_parser_omp_scope (parser, pragma_tok, if_p); + break; case PRAGMA_OMP_SECTIONS: strcpy (p_name, "#pragma omp"); stmt = cp_parser_omp_sections (parser, pragma_tok, p_name, mask, NULL); @@ -46604,6 +46631,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case PRAGMA_OMP_MASKED: case PRAGMA_OMP_MASTER: case PRAGMA_OMP_PARALLEL: + case PRAGMA_OMP_SCOPE: case PRAGMA_OMP_SECTIONS: case PRAGMA_OMP_SIMD: case PRAGMA_OMP_SINGLE: diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0870ccd..484723b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -18791,6 +18791,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, omp_parallel_combined_clauses = NULL; /* FALLTHRU */ case OMP_SINGLE: + case OMP_SCOPE: case OMP_TEAMS: case OMP_CRITICAL: case OMP_TASKGROUP: -- 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/class.c | 30 ------ gcc/cp/constexpr.c | 12 +++ gcc/cp/constraint.cc | 3 + gcc/cp/cp-gimplify.c | 13 +++ gcc/cp/cp-objcp-common.c | 1 + gcc/cp/cp-tree.h | 5 + gcc/cp/cxx-pretty-print.c | 4 + gcc/cp/decl.c | 7 ++ gcc/cp/parser.c | 5 + gcc/cp/semantics.c | 268 ++++++++++++++++++++++++++++++++++++++++++++++ gcc/cp/tree.c | 1 + gcc/cp/typeck.c | 170 +++++++++++++++++++++++++++++ 12 files changed, 489 insertions(+), 30 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 6f31700..7138e30 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -136,7 +136,6 @@ static bool check_field_decl (tree, tree, int *, int *); static void check_field_decls (tree, tree *, int *, int *); static void build_base_fields (record_layout_info, splay_tree, tree *); static void check_methods (tree); -static void remove_zero_width_bit_fields (tree); static bool accessible_nvdtor_p (tree); /* Used by find_flexarrays and related functions. */ @@ -5754,31 +5753,6 @@ type_build_dtor_call (tree t) return false; } -/* Remove all zero-width bit-fields from T. */ - -static void -remove_zero_width_bit_fields (tree t) -{ - tree *fieldsp; - - fieldsp = &TYPE_FIELDS (t); - while (*fieldsp) - { - if (TREE_CODE (*fieldsp) == FIELD_DECL - && DECL_C_BIT_FIELD (*fieldsp) - /* We should not be confused by the fact that grokbitfield - temporarily sets the width of the bit field into - DECL_BIT_FIELD_REPRESENTATIVE (*fieldsp). - check_bitfield_decl eventually sets DECL_SIZE (*fieldsp) - to that width. */ - && (DECL_SIZE (*fieldsp) == NULL_TREE - || integer_zerop (DECL_SIZE (*fieldsp)))) - *fieldsp = DECL_CHAIN (*fieldsp); - else - fieldsp = &DECL_CHAIN (*fieldsp); - } -} - /* Returns TRUE iff we need a cookie when dynamically allocating an array whose elements have the indicated class TYPE. */ @@ -6770,10 +6744,6 @@ layout_class_type (tree t, tree *virtuals_p) normalize_rli (rli); } - /* Delete all zero-width bit-fields from the list of fields. Now - that the type is laid out they are no longer important. */ - remove_zero_width_bit_fields (t); - if (CLASSTYPE_NON_LAYOUT_POD_P (t) || CLASSTYPE_EMPTY_P (t)) { /* T needs a different layout as a base (eliding virtual bases diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 25d84a3..b9c0062 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1438,6 +1438,18 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, = fold_builtin_is_pointer_inverconvertible_with_class (loc, nargs, args); } + else if (fndecl_built_in_p (fun, + CP_BUILT_IN_IS_CORRESPONDING_MEMBER, + BUILT_IN_FRONTEND)) + { + location_t loc = EXPR_LOCATION (t); + if (nargs >= 2) + { + VERIFY_CONSTANT (args[0]); + VERIFY_CONSTANT (args[1]); + } + new_call = fold_builtin_is_corresponding_member (loc, nargs, args); + } else new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), CALL_EXPR_FN (t), nargs, args); diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index e608c5a..1aaf1e2 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3628,6 +3628,9 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_IS_FINAL: inform (loc, " %qT is not a final class", t1); break; + case CPTK_IS_LAYOUT_COMPATIBLE: + inform (loc, " %qT is not layout compatible with %qT", t1, t2); + break; case CPTK_IS_LITERAL_TYPE: inform (loc, " %qT is not a literal type", t1); break; diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 6e274ac..bf928a8 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -658,12 +658,20 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) *expr_p = fold_builtin_source_location (EXPR_LOCATION (*expr_p)); break; + case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: + *expr_p + = fold_builtin_is_corresponding_member + (EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p), + &CALL_EXPR_ARG (*expr_p, 0)); + break; case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: *expr_p = fold_builtin_is_pointer_inverconvertible_with_class (EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p), &CALL_EXPR_ARG (*expr_p, 0)); break; + default: + break; } } break; @@ -2579,6 +2587,11 @@ cp_fold (tree x) case CP_BUILT_IN_SOURCE_LOCATION: x = fold_builtin_source_location (EXPR_LOCATION (x)); break; + case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: + x = fold_builtin_is_corresponding_member + (EXPR_LOCATION (x), call_expr_nargs (x), + &CALL_EXPR_ARG (x, 0)); + break; case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: x = fold_builtin_is_pointer_inverconvertible_with_class (EXPR_LOCATION (x), call_expr_nargs (x), diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index beef012..98fd962 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -413,6 +413,7 @@ names_builtin_p (const char *name) case RID_IS_EMPTY: case RID_IS_ENUM: case RID_IS_FINAL: + case RID_IS_LAYOUT_COMPATIBLE: case RID_IS_LITERAL_TYPE: case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: case RID_IS_POD: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bd3f12a..14e2db2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1365,6 +1365,7 @@ enum cp_trait_kind CPTK_IS_EMPTY, CPTK_IS_ENUM, CPTK_IS_FINAL, + CPTK_IS_LAYOUT_COMPATIBLE, CPTK_IS_LITERAL_TYPE, CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, CPTK_IS_POD, @@ -6358,6 +6359,7 @@ struct GTY((chain_next ("%h.next"))) tinst_level { enum cp_built_in_function { CP_BUILT_IN_IS_CONSTANT_EVALUATED, CP_BUILT_IN_INTEGER_PACK, + CP_BUILT_IN_IS_CORRESPONDING_MEMBER, CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, CP_BUILT_IN_SOURCE_LOCATION, CP_BUILT_IN_LAST @@ -7574,6 +7576,7 @@ extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, bool, bool); extern tree finish_decltype_type (tree, bool, tsubst_flags_t); +extern tree fold_builtin_is_corresponding_member (location_t, int, tree *); extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *); extern tree finish_trait_expr (location_t, enum cp_trait_kind, tree, tree); extern tree build_lambda_expr (void); @@ -7800,6 +7803,8 @@ extern bool comp_except_specs (const_tree, const_tree, int); extern bool comptypes (tree, tree, int); extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree); extern bool similar_type_p (tree, tree); +extern bool next_common_initial_seqence (tree &, tree &); +extern bool layout_compatible_type_p (tree, tree); extern bool compparms (const_tree, const_tree); extern int comp_cv_qualification (const_tree, const_tree); extern int comp_cv_qualification (int, int); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index b899162..25cabfe 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2645,6 +2645,9 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) case CPTK_IS_FINAL: pp_cxx_ws_string (pp, "__is_final"); break; + case CPTK_IS_LAYOUT_COMPATIBLE: + pp_cxx_ws_string (pp, "__is_layout_compatible"); + break; case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF: pp_cxx_ws_string (pp, "__is_pointer_interconvertible_base_of"); break; @@ -2700,6 +2703,7 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) if (kind == CPTK_IS_BASE_OF || kind == CPTK_IS_SAME_AS + || kind == CPTK_IS_LAYOUT_COMPATIBLE || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF) { pp_cxx_separate_with (pp, ','); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b3671ee..32d07ba 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4470,6 +4470,13 @@ cxx_init_decl_processing (void) tree bool_vaftype = build_varargs_function_type_list (boolean_type_node, NULL_TREE); decl + = add_builtin_function ("__builtin_is_corresponding_member", + bool_vaftype, + CP_BUILT_IN_IS_CORRESPONDING_MEMBER, + BUILT_IN_FRONTEND, NULL, NULL_TREE); + set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF); + + decl = add_builtin_function ("__builtin_is_pointer_interconvertible_with_class", bool_vaftype, CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c31965a..9de72f8 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -5816,6 +5816,7 @@ cp_parser_primary_expression (cp_parser *parser, case RID_IS_EMPTY: case RID_IS_ENUM: case RID_IS_FINAL: + case RID_IS_LAYOUT_COMPATIBLE: case RID_IS_LITERAL_TYPE: case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: case RID_IS_POD: @@ -10707,6 +10708,10 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) case RID_IS_FINAL: kind = CPTK_IS_FINAL; break; + case RID_IS_LAYOUT_COMPATIBLE: + kind = CPTK_IS_LAYOUT_COMPATIBLE; + binary = true; + break; case RID_IS_LITERAL_TYPE: kind = CPTK_IS_LITERAL_TYPE; break; 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 (); } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index e8831b2..3c62dd7 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -455,6 +455,7 @@ builtin_valid_in_constant_expr_p (const_tree decl) { case CP_BUILT_IN_IS_CONSTANT_EVALUATED: case CP_BUILT_IN_SOURCE_LOCATION: + case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: return true; default: diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 738e69a..a46c6d2 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1621,6 +1621,176 @@ similar_type_p (tree type1, tree type2) return false; } +/* Helper function for layout_compatible_type_p and + is_corresponding_member_aggr. Advance to next members (NULL if + no further ones) and return true if those members are still part of + the common initial sequence. */ + +bool +next_common_initial_seqence (tree &memb1, tree &memb2) +{ + while (memb1) + { + if (TREE_CODE (memb1) != FIELD_DECL + || (DECL_FIELD_IS_BASE (memb1) && is_empty_field (memb1))) + { + memb1 = DECL_CHAIN (memb1); + continue; + } + if (DECL_FIELD_IS_BASE (memb1)) + { + memb1 = TYPE_FIELDS (TREE_TYPE (memb1)); + continue; + } + break; + } + while (memb2) + { + if (TREE_CODE (memb2) != FIELD_DECL + || (DECL_FIELD_IS_BASE (memb2) && is_empty_field (memb2))) + { + memb2 = DECL_CHAIN (memb2); + continue; + } + if (DECL_FIELD_IS_BASE (memb2)) + { + memb2 = TYPE_FIELDS (TREE_TYPE (memb2)); + continue; + } + break; + } + if (memb1 == NULL_TREE && memb2 == NULL_TREE) + return true; + if (memb1 == NULL_TREE || memb2 == NULL_TREE) + return false; + if (DECL_BIT_FIELD_TYPE (memb1)) + { + if (!DECL_BIT_FIELD_TYPE (memb2)) + return false; + if (!layout_compatible_type_p (DECL_BIT_FIELD_TYPE (memb1), + DECL_BIT_FIELD_TYPE (memb2))) + return false; + if (TYPE_PRECISION (TREE_TYPE (memb1)) + != TYPE_PRECISION (TREE_TYPE (memb2))) + return false; + } + else if (DECL_BIT_FIELD_TYPE (memb2)) + return false; + else if (!layout_compatible_type_p (TREE_TYPE (memb1), TREE_TYPE (memb2))) + return false; + if ((!lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (memb1))) + != !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (memb2))) + return false; + if (!tree_int_cst_equal (bit_position (memb1), bit_position (memb2))) + return false; + return true; +} + +/* Return true if TYPE1 and TYPE2 are layout-compatible types. */ + +bool +layout_compatible_type_p (tree type1, tree type2) +{ + if (type1 == error_mark_node || type2 == error_mark_node) + return false; + if (type1 == type2) + return true; + if (TREE_CODE (type1) != TREE_CODE (type2)) + return false; + + type1 = cp_build_qualified_type (type1, TYPE_UNQUALIFIED); + type2 = cp_build_qualified_type (type2, TYPE_UNQUALIFIED); + + if (TREE_CODE (type1) == ENUMERAL_TYPE) + return (TYPE_ALIGN (type1) == TYPE_ALIGN (type2) + && tree_int_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2)) + && same_type_p (finish_underlying_type (type1), + finish_underlying_type (type2))); + + if (CLASS_TYPE_P (type1) + && std_layout_type_p (type1) + && std_layout_type_p (type2) + && TYPE_ALIGN (type1) == TYPE_ALIGN (type2) + && tree_int_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2))) + { + tree field1 = TYPE_FIELDS (type1); + tree field2 = TYPE_FIELDS (type2); + if (TREE_CODE (type1) == RECORD_TYPE) + { + while (1) + { + if (!next_common_initial_seqence (field1, field2)) + return false; + if (field1 == NULL_TREE) + return true; + field1 = DECL_CHAIN (field1); + field2 = DECL_CHAIN (field2); + } + } + /* Otherwise both types must be union types. + The standard says: + "Two standard-layout unions are layout-compatible if they have + the same number of non-static data members and corresponding + non-static data members (in any order) have layout-compatible + types." + but the code anticipates that bitfield vs. non-bitfield, + different bitfield widths or presence/absence of + [[no_unique_address]] should be checked as well. */ + auto_vec vec; + unsigned int count = 0; + for (; field1; field1 = DECL_CHAIN (field1)) + if (TREE_CODE (field1) == FIELD_DECL) + count++; + for (; field2; field2 = DECL_CHAIN (field2)) + if (TREE_CODE (field2) == FIELD_DECL) + vec.safe_push (field2); + /* Discussions on core lean towards treating multiple union fields + of the same type as the same field, so this might need changing + in the future. */ + if (count != vec.length ()) + return false; + for (field1 = TYPE_FIELDS (type1); field1; field1 = DECL_CHAIN (field1)) + { + if (TREE_CODE (field1) != FIELD_DECL) + continue; + unsigned int j; + tree t1 = DECL_BIT_FIELD_TYPE (field1); + if (t1 == NULL_TREE) + t1 = TREE_TYPE (field1); + FOR_EACH_VEC_ELT (vec, j, field2) + { + tree t2 = DECL_BIT_FIELD_TYPE (field2); + if (t2 == NULL_TREE) + t2 = TREE_TYPE (field2); + if (DECL_BIT_FIELD_TYPE (field1)) + { + if (!DECL_BIT_FIELD_TYPE (field2)) + continue; + if (TYPE_PRECISION (TREE_TYPE (field1)) + != TYPE_PRECISION (TREE_TYPE (field2))) + continue; + } + else if (DECL_BIT_FIELD_TYPE (field2)) + continue; + if (!layout_compatible_type_p (t1, t2)) + continue; + if ((!lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field1))) + != !lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field2))) + continue; + break; + } + if (j == vec.length ()) + return false; + vec.unordered_remove (j); + } + return true; + } + + return same_type_p (type1, type2); +} + /* Returns 1 if TYPE1 is at least as qualified as TYPE2. */ bool -- cgit v1.1 From 2d14d64bf2d42a87ec58dd3760be12aeaa4a4279 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 18 Aug 2021 00:16:48 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7a4a707..a2d47b3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,44 @@ +2021-08-17 Jakub Jelinek + + PR c++/101539 + * 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. + +2021-08-17 Jakub Jelinek + + * parser.c (OMP_SCOPE_CLAUSE_MASK): Define. + (cp_parser_omp_scope): New function. + (cp_parser_omp_construct, cp_parser_pragma): Handle PRAGMA_OMP_SCOPE. + * pt.c (tsubst_expr): Handle OMP_SCOPE. + 2021-08-12 Jakub Jelinek * parser.c (cp_parser_omp_clause_name): Parse filter clause name. -- cgit v1.1 From 1bf976a5de69ecd9b1e10eb7515357b98e78faf7 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 18 Aug 2021 10:20:50 +0200 Subject: openmp: Actually ignore pragma_stmt pragmas for which c_parser_pragma returns false Unlike the C++ FE, the C FE ignored pragmas (as if they weren't there) in pragma_stmt contexts if c*_parser_pragma returns false only when after labels, not inside of substatements of selection or loop statements. After making just that change, several gomp/goacc testcases started failing, because extra diagnostics has been emitted (in C, in C++ it was emitted already before). Say void foo (int x) { if (x) #pragma omp barrier } used to in C emit just an error that the pragma is not allowed in such contexts, but in C++ emitted both that and a parsing error that if (x) } is invalid. So, the rest of this patch is mostly about returning true after we report that that certain pragma is not allowed in pragma_stmt contexts, because for error-recovery it seems better to treat the pragma in that case as something that is the substatement of such if etc. c*_parser_pragma return value is only ever used for pragma_stmt context, in which false means act as if the pragma isn't there (e.g. has been handled already by preprocessor etc.), and true which means it was there. 2021-08-18 Jakub Jelinek gcc/c/ * c-parser.c (c_parser_statement_after_labels): Add restart label near the start of the function. If c_parser_pragma returns false, goto restart. (c_parser_pragma): For PRAGMA_OMP_CANCELLATION_POINT return what c_parser_omp_cancellation_point returned. For PRAGMA_OMP_DECLARE return what c_parser_omp_declare returned. Return true instead of false after emitting errors that the directive is not allowed in pragma_stmt context. (c_parser_omp_ordered): Return true instead of false after emitting errors that the directive is not allowed in pragma_stmt context. (c_parser_omp_target_update): Likewise. (c_parser_omp_target_enter_data, c_parser_omp_target_exit_data): Change return type from tree to bool, return false if the directive should be ignored in pragma_stmt contexts. (c_parser_omp_target): Adjust callers of c_parser_omp_target_*_data, return their result directly. (c_parser_omp_cancellation_point): Change return type from void to bool, return false if the directive should be ignored in pragma_stmt contexts. (c_parser_omp_declare): Likewise. gcc/cp/ * parser.c (cp_parser_omp_ordered): Return true instead of false after emitting errors that the directive is not allowed in pragma_stmt context. (cp_parser_omp_target_update): Likewise. (cp_parser_omp_cancellation_point): Change return type from void to bool, return false if the directive should be ignored in pragma_stmt contexts. (cp_parser_omp_target_enter_data, cp_parser_omp_target_exit_data): Change return type from tree to bool, return false if the directive should be ignored in pragma_stmt contexts. (cp_parser_omp_target): Adjust callers of cp_parser_omp_target_*_data, return their result directly. (cp_parser_pragma): For PRAGMA_OMP_CANCELLATION_POINT return what cp_parser_omp_cancellation_point returned. Return true instead of false after emitting errors that the directive is not allowed in pragma_stmt context. gcc/testsuite/ * c-c++-common/gomp/pr63326.c: Don't expect extra "before" errors in C++. * g++.dg/gomp/attrs-7.C: Don't expect one extra error. * g++.dg/gomp/barrier-2.C: Likewise. * gcc.dg/gomp/declare-simd-5.c: Likewise. * gcc.dg/gomp/barrier-2.c: Likewise. * gcc.dg/gomp/declare-variant-2.c: Likewise. --- gcc/cp/parser.c | 62 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 25 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 9de72f8..8f2d0fc 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -42137,7 +42137,7 @@ cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok, "% clause may only be used in compound " "statements"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return true; } tree clauses = cp_parser_omp_all_clauses (parser, @@ -42661,7 +42661,7 @@ cp_parser_omp_cancel (cp_parser *parser, cp_token *pragma_tok) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) -static void +static bool cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -42683,7 +42683,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return; + return false; } if (context != pragma_compound) @@ -42695,7 +42695,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, else cp_parser_error (parser, "expected declaration specifiers"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return; + return true; } clauses = cp_parser_omp_all_clauses (parser, @@ -42703,6 +42703,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, "#pragma omp cancellation point", pragma_tok); finish_omp_cancellation_point (clauses); + return true; } /* OpenMP 4.0: @@ -42998,7 +42999,7 @@ cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok, bool *if_p) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -43018,7 +43019,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -43027,7 +43028,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target enter data"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return true; } tree clauses @@ -43067,14 +43068,15 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target enter data%> must contain at least " "one % clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_ENTER_DATA); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); - return add_stmt (stmt); + add_stmt (stmt); + return true; } /* OpenMP 4.5: @@ -43088,7 +43090,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -43108,7 +43110,7 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -43117,7 +43119,7 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target exit data"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return true; } tree clauses @@ -43159,14 +43161,15 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target exit data%> must contain at least " "one % clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_EXIT_DATA); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); - return add_stmt (stmt); + add_stmt (stmt); + return true; } /* OpenMP 4.0: @@ -43190,7 +43193,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target update"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return true; } tree clauses @@ -43202,7 +43205,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target update%> must contain at least one " "% or % clauses"); - return false; + return true; } tree stmt = make_node (OMP_TARGET_UPDATE); @@ -43210,7 +43213,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); add_stmt (stmt); - return false; + return true; } /* OpenMP 4.0: @@ -43364,14 +43367,12 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, else if (strcmp (p, "enter") == 0) { cp_lexer_consume_token (parser->lexer); - cp_parser_omp_target_enter_data (parser, pragma_tok, context); - return false; + return cp_parser_omp_target_enter_data (parser, pragma_tok, context); } else if (strcmp (p, "exit") == 0) { cp_lexer_consume_token (parser->lexer); - cp_parser_omp_target_exit_data (parser, pragma_tok, context); - return false; + return cp_parser_omp_target_exit_data (parser, pragma_tok, context); } else if (strcmp (p, "update") == 0) { @@ -46432,7 +46433,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) cp_token *pragma_tok; unsigned int id; tree stmt; - bool ret; + bool ret = false; pragma_tok = cp_lexer_consume_token (parser->lexer); gcc_assert (pragma_tok->type == CPP_PRAGMA); @@ -46457,6 +46458,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp barrier"); + ret = true; break; default: goto bad_stmt; @@ -46472,6 +46474,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp depobj"); + ret = true; break; default: goto bad_stmt; @@ -46487,6 +46490,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp flush"); + ret = true; break; default: goto bad_stmt; @@ -46503,6 +46507,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp taskwait"); + ret = true; break; default: goto bad_stmt; @@ -46519,6 +46524,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp taskyield"); + ret = true; break; default: goto bad_stmt; @@ -46535,6 +46541,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp cancel"); + ret = true; break; default: goto bad_stmt; @@ -46542,8 +46549,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) break; case PRAGMA_OMP_CANCELLATION_POINT: - cp_parser_omp_cancellation_point (parser, pragma_tok, context); - return false; + return cp_parser_omp_cancellation_point (parser, pragma_tok, context); case PRAGMA_OMP_THREADPRIVATE: cp_parser_omp_threadprivate (parser, pragma_tok); @@ -46562,6 +46568,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc enter data"); + ret = true; break; } else if (context != pragma_compound) @@ -46575,6 +46582,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc exit data"); + ret = true; break; } else if (context != pragma_compound) @@ -46587,6 +46595,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) { error_at (pragma_tok->location, "%<#pragma acc routine%> must be at file scope"); + ret = true; break; } cp_parser_oacc_routine (parser, pragma_tok, context); @@ -46598,6 +46607,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc update"); + ret = true; break; } else if (context != pragma_compound) @@ -46611,6 +46621,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc wait"); + ret = true; break; } else if (context != pragma_compound) @@ -46657,6 +46668,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma omp requires%> may only be used at file or " "namespace scope"); + ret = true; break; } return cp_parser_omp_requires (parser, pragma_tok); @@ -46769,7 +46781,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) } cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return ret; } /* The interface the pragma parsers have to the lexer. */ -- cgit v1.1 From 5079b7781a2c506dcdfb241347d74c7891268225 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 18 Aug 2021 11:10:43 +0200 Subject: openmp: Add nothing directive support As has been clarified, it is intentional that nothing directive is accepted in substatements of selection and looping statements and after labels and is handled as if the directive just isn't there, so that void foo (int x) { if (x) #pragma omp metadirective when (...:nothing) when (...:parallel) bar (); } behaves consistently; declarative and stand-alone directives aren't allowed at that point, but constructs are parsed with the following statement as the construct body and nothing or missing default on metadirective therefore should handle the following statement as part of the if substatement instead of having nothing as the substatement and bar done unconditionally after the if. 2021-08-18 Jakub Jelinek gcc/c-family/ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_NOTHING. * c-pragma.c (omp_pragmas): Add nothing directive. * c-omp.c (omp_directives): Uncomment nothing directive entry. gcc/c/ * c-parser.c (c_parser_omp_nothing): New function. (c_parser_pragma): Handle PRAGMA_OMP_NOTHING. gcc/cp/ * parser.c (cp_parser_omp_nothing): New function. (cp_parser_pragma): Handle PRAGMA_OMP_NOTHING. gcc/testsuite/ * c-c++-common/gomp/nothing-1.c: New test. * g++.dg/gomp/attrs-1.C (bar): Add nothing directive test. * g++.dg/gomp/attrs-2.C (bar): Likewise. * g++.dg/gomp/attrs-9.C: Likewise. libgomp/ * testsuite/libgomp.c-c++-common/nothing-1.c: New test. --- gcc/cp/parser.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 8f2d0fc..04116fb 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -45564,6 +45564,16 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok) } +/* OpenMP 5.1: + #pragma omp nothing new-line */ + +static void +cp_parser_omp_nothing (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_skip_to_pragma_eol (parser, pragma_tok); +} + + /* OpenMP 4.5: #pragma omp taskloop taskloop-clause[optseq] new-line for-loop @@ -46673,6 +46683,10 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) } return cp_parser_omp_requires (parser, pragma_tok); + case PRAGMA_OMP_NOTHING: + cp_parser_omp_nothing (parser, pragma_tok); + return false; + case PRAGMA_OMP_ORDERED: if (context != pragma_stmt && context != pragma_compound) goto bad_stmt; -- cgit v1.1 From a6b3db3e8625a3cba1240f0b5e1a29bd6c68b8ca Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 18 Aug 2021 08:37:42 -0400 Subject: c++: ignore explicit dguides during NTTP CTAD [PR101883] Since (template) argument passing is a copy-initialization context, we mustn't consider explicit deduction guides when deducing a CTAD placeholder type of an NTTP. PR c++/101883 gcc/cp/ChangeLog: * pt.c (convert_template_argument): Pass LOOKUP_IMPLICIT to do_auto_deduction. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/nontype-class49.C: New test. --- gcc/cp/pt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 484723b..0c14966 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8486,7 +8486,8 @@ convert_template_argument (tree parm, can happen in the context of -fnew-ttp-matching. */; else if (tree a = type_uses_auto (t)) { - t = do_auto_deduction (t, arg, a, complain, adc_unify, args); + t = do_auto_deduction (t, arg, a, complain, adc_unify, args, + LOOKUP_IMPLICIT); if (t == error_mark_node) return error_mark_node; } -- cgit v1.1 From be4a4fb516688d7cfe28a80a4aa333f4ecf0b518 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 18 Aug 2021 08:37:45 -0400 Subject: c++: aggregate CTAD and brace elision [PR101344] Here the problem is ultimately that collect_ctor_idx_types always recurses into an eligible sub-CONSTRUCTOR regardless of whether the corresponding pair of braces was elided in the original initializer. This causes us to reject some completely-braced forms of aggregate CTAD as in the first testcase below, because collect_ctor_idx_types effectively assumes that the original initializer is always minimally braced (and so the aggregate deduction candidate is given a function type that's incompatible with the original completely-braced initializer). In order to fix this, collect_ctor_idx_types needs to somehow know the shape of the original initializer when iterating over the reshaped initializer. To that end this patch makes reshape_init flag sub-ctors that were built to undo brace elision in the original ctor, so that collect_ctor_idx_types that determine whether to recurse into a sub-ctor by simply inspecting this flag. This happens to also fix PR101820, which is about aggregate CTAD using designated initializers, for much the same reasons. A curious case is the "intermediately-braced" initialization of 'e3' (which we reject) in the first testcase below. It seems to me we're behaving as specified here (according to [over.match.class.deduct]/1) because the initializer element x_1={1, 2, 3, 4} corresponds to the subobject e_1=E::t, hence the type T_1 of the first function parameter of the aggregate deduction candidate is T(&&)[2][2], but T can't be deduced from x_1 using this parameter type (as opposed to say T(&&)[4]). PR c++/101344 PR c++/101820 gcc/cp/ChangeLog: * cp-tree.h (CONSTRUCTOR_BRACES_ELIDED_P): Define. * decl.c (reshape_init_r): Set it. * pt.c (collect_ctor_idx_types): Recurse into a sub-CONSTRUCTOR iff CONSTRUCTOR_BRACES_ELIDED_P. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-aggr11.C: New test. * g++.dg/cpp2a/class-deduction-aggr12.C: New test. --- gcc/cp/cp-tree.h | 6 ++++++ gcc/cp/decl.c | 18 ++++++++++++++---- gcc/cp/pt.c | 7 +------ 3 files changed, 21 insertions(+), 10 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 14e2db2..7ba02be 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4503,6 +4503,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define CONSTRUCTOR_IS_PAREN_INIT(NODE) \ (CONSTRUCTOR_CHECK(NODE)->base.private_flag) +/* True if reshape_init built this CONSTRUCTOR to undo the brace elision + of another CONSTRUCTOR. This flag is used during C++20 aggregate + CTAD. */ +#define CONSTRUCTOR_BRACES_ELIDED_P(NODE) \ + (CONSTRUCTOR_CHECK (NODE)->base.protected_flag) + /* True if NODE represents a conversion for direct-initialization in a template. Set by perform_implicit_conversion_flags. */ #define IMPLICIT_CONV_EXPR_DIRECT_INIT(NODE) \ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 32d07ba..3414cbd 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6657,7 +6657,8 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, /* A non-aggregate type is always initialized with a single initializer. */ if (!CP_AGGREGATE_TYPE_P (type) - /* As is an array with dependent bound. */ + /* As is an array with dependent bound, which we can see + during C++20 aggregate CTAD. */ || (cxx_dialect >= cxx20 && TREE_CODE (type) == ARRAY_TYPE && uses_template_parms (TYPE_DOMAIN (type)))) @@ -6774,6 +6775,7 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, initializer already, and there is not a CONSTRUCTOR, it means that there is a missing set of braces (that is, we are processing the case for which reshape_init exists). */ + bool braces_elided_p = false; if (!first_initializer_p) { if (TREE_CODE (stripped_init) == CONSTRUCTOR) @@ -6809,17 +6811,25 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, warning (OPT_Wmissing_braces, "missing braces around initializer for %qT", type); + braces_elided_p = true; } /* Dispatch to specialized routines. */ + tree new_init; if (CLASS_TYPE_P (type)) - return reshape_init_class (type, d, first_initializer_p, complain); + new_init = reshape_init_class (type, d, first_initializer_p, complain); else if (TREE_CODE (type) == ARRAY_TYPE) - return reshape_init_array (type, d, first_initializer_p, complain); + new_init = reshape_init_array (type, d, first_initializer_p, complain); else if (VECTOR_TYPE_P (type)) - return reshape_init_vector (type, d, complain); + new_init = reshape_init_vector (type, d, complain); else gcc_unreachable(); + + if (braces_elided_p + && TREE_CODE (new_init) == CONSTRUCTOR) + CONSTRUCTOR_BRACES_ELIDED_P (new_init) = true; + + return new_init; } /* Undo the brace-elision allowed by [dcl.init.aggr] in a diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0c14966..020a4bf 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -28837,12 +28837,7 @@ collect_ctor_idx_types (tree ctor, tree list, tree elt = NULL_TREE) { tree ftype = elt ? elt : TREE_TYPE (idx); if (BRACE_ENCLOSED_INITIALIZER_P (val) - && CONSTRUCTOR_NELTS (val) - /* As in reshape_init_r, a non-aggregate or array-of-dependent-bound - type gets a single initializer. */ - && CP_AGGREGATE_TYPE_P (ftype) - && !(TREE_CODE (ftype) == ARRAY_TYPE - && uses_template_parms (TYPE_DOMAIN (ftype)))) + && CONSTRUCTOR_BRACES_ELIDED_P (val)) { tree subelt = NULL_TREE; if (TREE_CODE (ftype) == ARRAY_TYPE) -- cgit v1.1 From 6e529985d8956f74492e3176026fc02dc8f01b6c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 19 Aug 2021 00:16:42 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a2d47b3..a06a496 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,42 @@ +2021-08-18 Patrick Palka + + PR c++/101344 + PR c++/101820 + * cp-tree.h (CONSTRUCTOR_BRACES_ELIDED_P): Define. + * decl.c (reshape_init_r): Set it. + * pt.c (collect_ctor_idx_types): Recurse into a sub-CONSTRUCTOR + iff CONSTRUCTOR_BRACES_ELIDED_P. + +2021-08-18 Patrick Palka + + PR c++/101883 + * pt.c (convert_template_argument): Pass LOOKUP_IMPLICIT to + do_auto_deduction. + +2021-08-18 Jakub Jelinek + + * parser.c (cp_parser_omp_nothing): New function. + (cp_parser_pragma): Handle PRAGMA_OMP_NOTHING. + +2021-08-18 Jakub Jelinek + + * parser.c (cp_parser_omp_ordered): Return true instead of + false after emitting errors that the directive is not allowed in + pragma_stmt context. + (cp_parser_omp_target_update): Likewise. + (cp_parser_omp_cancellation_point): Change return type from void to + bool, return false if the directive should be ignored in pragma_stmt + contexts. + (cp_parser_omp_target_enter_data, cp_parser_omp_target_exit_data): + Change return type from tree to bool, return false if the + directive should be ignored in pragma_stmt contexts. + (cp_parser_omp_target): Adjust callers of cp_parser_omp_target_*_data, + return their result directly. + (cp_parser_pragma): For PRAGMA_OMP_CANCELLATION_POINT return what + cp_parser_omp_cancellation_point returned. Return true instead of + false after emitting errors that the directive is not allowed in + pragma_stmt context. + 2021-08-17 Jakub Jelinek PR c++/101539 -- cgit v1.1 From 4e6a5fa403782590088b2796261b023963f912af Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 19 Aug 2021 10:35:39 +0200 Subject: openmp: For C++ ensure nothing directive has no operands When working on error directive, I've noticed that while C FE diagnosed clauses on nothing directive which doesn't allow any, the C++ FE silently accepted it. 2021-08-19 Jakub Jelinek * parser.c (cp_parser_omp_nothing): Use cp_parser_require_pragma_eol instead of cp_parser_skip_to_pragma_eol. * c-c++-common/gomp/nothing-2.c: New test. --- gcc/cp/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 04116fb..1d48b83 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -45570,7 +45570,7 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok) static void cp_parser_omp_nothing (cp_parser *parser, cp_token *pragma_tok) { - cp_parser_skip_to_pragma_eol (parser, pragma_tok); + cp_parser_require_pragma_eol (parser, pragma_tok); } -- cgit v1.1 From c04d766942274da89b236c4cb7e954b26da397c7 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 19 Aug 2021 10:38:19 +0200 Subject: openmp: Fix ICE on requires clause with atomic_default_mem_order ( When working on error directive, I've noticed the C FE ICEs on #pragma omp requires atomic_default_mem_order ( where it tries to peek 2nd token after the CPP_PRAGMA_EOL (or CPP_EOF) in there in order to improve error-recovery on say atomic_default_mem_order (acquire) or atomic_default_mem_order (seqcst) etc. The C++ FE didn't ICE, but it is better to follow the same thing there. 2021-08-19 Jakub Jelinek gcc/c/ * c-parser.c (c_parser_omp_requires): Don't call c_parser_peek_2nd_token and optionally consume token if current token is CPP_EOF, CPP_PRAGMA_EOL or CPP_CLOSE_PAREN. gcc/cp/ * parser.c (cp_parser_omp_requires): Don't call cp_lexer_nth_token_is and optionally consume token if current token is CPP_EOF, CPP_PRAGMA_EOL or CPP_CLOSE_PAREN. gcc/testsuite/ * c-c++-common/gomp/requires-3.c: Add testcase for atomic_default_mem_order ( at the end of line without corresponding ). --- gcc/cp/parser.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1d48b83..0af1a2c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -45479,9 +45479,18 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok) error_at (cp_lexer_peek_token (parser->lexer)->location, "expected %, % or " "%"); - if (cp_lexer_nth_token_is (parser->lexer, 2, - CPP_CLOSE_PAREN)) - cp_lexer_consume_token (parser->lexer); + switch (cp_lexer_peek_token (parser->lexer)->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + case CPP_CLOSE_PAREN: + break; + default: + if (cp_lexer_nth_token_is (parser->lexer, 2, + CPP_CLOSE_PAREN)) + cp_lexer_consume_token (parser->lexer); + break; + } } else cp_lexer_consume_token (parser->lexer); -- cgit v1.1 From 0c0907f99155366e9f3560c29ac37eb0e2880254 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 19 Aug 2021 09:05:35 -0400 Subject: Fix PR number for r12-2991 in ChangeLogs --- gcc/cp/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a06a496..6f872f6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,7 +1,7 @@ 2021-08-18 Patrick Palka PR c++/101344 - PR c++/101820 + PR c++/101803 * cp-tree.h (CONSTRUCTOR_BRACES_ELIDED_P): Define. * decl.c (reshape_init_r): Set it. * pt.c (collect_ctor_idx_types): Recurse into a sub-CONSTRUCTOR -- cgit v1.1 From 4285ca3e1c4a6c9540dcdf1c4a71b99aba9bbfe8 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 19 Aug 2021 09:07:02 -0400 Subject: c++: Fix PR number in testcase [PR101803] Also clarify the description of CONSTRUCTOR_BRACES_ELIDED_P. PR c++/101803 gcc/cp/ChangeLog: * cp-tree.h (CONSTRUCTOR_IS_PAREN_INIT): Clarify comment. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-aggr12.C: Fix PR number. --- gcc/cp/cp-tree.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7ba02be..75ee887 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4503,8 +4503,8 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define CONSTRUCTOR_IS_PAREN_INIT(NODE) \ (CONSTRUCTOR_CHECK(NODE)->base.private_flag) -/* True if reshape_init built this CONSTRUCTOR to undo the brace elision - of another CONSTRUCTOR. This flag is used during C++20 aggregate +/* True if reshape_init built this sub-CONSTRUCTOR to undo the brace elision + of the original CONSTRUCTOR. This flag is used during C++20 aggregate CTAD. */ #define CONSTRUCTOR_BRACES_ELIDED_P(NODE) \ (CONSTRUCTOR_CHECK (NODE)->base.protected_flag) -- cgit v1.1 From b57fba5e376c7277168c14e207979e1505e6fe1d Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 20 Aug 2021 00:16:28 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6f872f6..f50c36c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2021-08-19 Patrick Palka + + PR c++/101803 + * cp-tree.h (CONSTRUCTOR_IS_PAREN_INIT): Clarify comment. + +2021-08-19 Jakub Jelinek + + * parser.c (cp_parser_omp_requires): Don't call cp_lexer_nth_token_is + and optionally consume token if current token is CPP_EOF, + CPP_PRAGMA_EOL or CPP_CLOSE_PAREN. + +2021-08-19 Jakub Jelinek + + * parser.c (cp_parser_omp_nothing): Use cp_parser_require_pragma_eol + instead of cp_parser_skip_to_pragma_eol. + 2021-08-18 Patrick Palka PR c++/101344 -- cgit v1.1 From f9400e4e4705845f2b0cdc4eab30c214e0e4cbe0 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 20 Aug 2021 11:29:48 +0200 Subject: openmp: Diagnose some superfluous commas in OpenMP parsing While working on error directive, I've noticed a few spots in OpenMP parsing where we consume and don't diagnose superfluous commas at the end (either of depend sink arguments or at the end of requires pragma). 2021-08-20 Jakub Jelinek gcc/c/ * c-parser.c (c_parser_omp_clause_depend_sink): Reject spurious comma at the end of list. (c_parser_omp_requires): Likewise. gcc/cp/ * parser.c (cp_parser_omp_clause_depend_sink): Reject spurious comma at the end of list. Don't parse closing paren here... (cp_parser_omp_clause_depend): ... but here instead. gcc/testsuite/ * c-c++-common/gomp/sink-5.c: New test. * c-c++-common/gomp/requires-3.c: Add test for spurious comma at the end of pragma line. --- gcc/cp/parser.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0af1a2c..d321364 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -38465,13 +38465,14 @@ cp_parser_omp_clause_depend_sink (cp_parser *parser, location_t clause_loc, OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1; } - if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA) + || !cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) break; cp_lexer_consume_token (parser->lexer); } - if (cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN) && vec) + if (vec) { tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK; @@ -38791,7 +38792,13 @@ cp_parser_omp_clause_depend (cp_parser *parser, tree list, location_t loc) goto resync_fail; if (kind == OMP_CLAUSE_DEPEND_SINK) - nlist = cp_parser_omp_clause_depend_sink (parser, loc, list); + { + nlist = cp_parser_omp_clause_depend_sink (parser, loc, list); + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + } else { nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_DEPEND, -- cgit v1.1 From 0d973c0a0d90a0a302e7eda1a4d9709be3c5b102 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 20 Aug 2021 11:36:52 +0200 Subject: openmp: Implement the error directive This patch implements the error directive. Depending on clauses it is either a compile time diagnostics (in that case diagnosed right away) or runtime diagnostics (libgomp API call that diagnoses at runtime), and either fatal or warning (error or warning at compile time or fatal error vs. error at runtime) and either has no message or user supplied message (this kind of e.g. deprecated attribute). The directive is also stand-alone directive when at runtime while utility (thus disappears from the IL as if it wasn't there for parsing like nothing directive) at compile time. There are some clarifications in the works ATM, so this patch doesn't yet require that for compile time diagnostics the user message must be a constant string literal, there are uncertainities on what exactly is valid argument of message clause (whether just const char * type, convertible to const char *, qualified/unqualified const char * or char * or what else) and what to do in templates. Currently even in templates it is diagnosed right away for compile time diagnostics, if we'll need to substitute it, we'd need to queue something into the IL, have pt.c handle it and diagnose only later. 2021-08-20 Jakub Jelinek gcc/ * omp-builtins.def (BUILT_IN_GOMP_WARNING, BUILT_IN_GOMP_ERROR): New builtins. gcc/c-family/ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_ERROR. * c-pragma.c (omp_pragmas): Add error directive. * c-omp.c (omp_directives): Uncomment error directive entry. gcc/c/ * c-parser.c (c_parser_omp_error): New function. (c_parser_pragma): Handle PRAGMA_OMP_ERROR. gcc/cp/ * parser.c (cp_parser_handle_statement_omp_attributes): Determine if PRAGMA_OMP_ERROR directive is C_OMP_DIR_STANDALONE. (cp_parser_omp_error): New function. (cp_parser_pragma): Handle PRAGMA_OMP_ERROR. gcc/fortran/ * types.def (BT_FN_VOID_CONST_PTR_SIZE): New DEF_FUNCTION_TYPE_2. * f95-lang.c (ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST): Define. gcc/testsuite/ * c-c++-common/gomp/error-1.c: New test. * c-c++-common/gomp/error-2.c: New test. * c-c++-common/gomp/error-3.c: New test. * g++.dg/gomp/attrs-1.C (bar): Add error directive test. * g++.dg/gomp/attrs-2.C (bar): Add error directive test. * g++.dg/gomp/attrs-13.C: New test. * g++.dg/gomp/error-1.C: New test. libgomp/ * libgomp.map (GOMP_5.1): Add GOMP_error and GOMP_warning. * libgomp_g.h (GOMP_warning, GOMP_error): Declare. * error.c (GOMP_warning, GOMP_error): New functions. * testsuite/libgomp.c-c++-common/error-1.c: New test. --- gcc/cp/parser.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d321364..63c9503 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11760,10 +11760,30 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) "depend") == 0) kind = C_OMP_DIR_STANDALONE; } - /* else if (dir->id == PRAGMA_OMP_ERROR) + else if (dir->id == PRAGMA_OMP_ERROR) { - error with at(execution) clause is C_OMP_DIR_STANDALONE. - } */ + /* error with at(execution) clause is C_OMP_DIR_STANDALONE. */ + int paren_depth = 0; + for (int i = 1; first + i < last; i++) + if (first[i].type == CPP_OPEN_PAREN) + paren_depth++; + else if (first[i].type == CPP_CLOSE_PAREN) + paren_depth--; + else if (paren_depth == 0 + && first + i + 2 < last + && first[i].type == CPP_NAME + && first[i + 1].type == CPP_OPEN_PAREN + && first[i + 2].type == CPP_NAME + && !strcmp (IDENTIFIER_POINTER (first[i].u.value), + "at") + && !strcmp (IDENTIFIER_POINTER (first[i + + 2].u.value), + "execution")) + { + kind = C_OMP_DIR_STANDALONE; + break; + } + } cp_omp_attribute_data v = { DEFPARSE_TOKENS (d), dir, kind }; vec.safe_push (v); if (flag_openmp || dir->simd) @@ -45590,6 +45610,184 @@ cp_parser_omp_nothing (cp_parser *parser, cp_token *pragma_tok) } +/* OpenMP 5.1 + #pragma omp error clauses[optseq] new-line */ + +static bool +cp_parser_omp_error (cp_parser *parser, cp_token *pragma_tok, + enum pragma_context context) +{ + int at_compilation = -1; + int severity_fatal = -1; + tree message = NULL_TREE; + bool first = true; + bool bad = false; + location_t loc = pragma_tok->location; + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) + { + /* For now only in C++ attributes, do it always for OpenMP 5.1. */ + if ((!first || parser->lexer->in_omp_attribute_pragma) + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + + first = false; + + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + break; + + const char *p + = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value); + location_t cloc = cp_lexer_peek_token (parser->lexer)->location; + static const char *args[] = { + "execution", "compilation", "warning", "fatal" + }; + int *v = NULL; + int idx = 0, n = -1; + tree m = NULL_TREE; + + if (!strcmp (p, "at")) + v = &at_compilation; + else if (!strcmp (p, "severity")) + { + v = &severity_fatal; + idx += 2; + } + else if (strcmp (p, "message")) + { + error_at (cloc, + "expected %, % or % clause"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return false; + } + + cp_lexer_consume_token (parser->lexer); + + matching_parens parens; + if (parens.require_open (parser)) + { + if (v == NULL) + { + m = cp_parser_assignment_expression (parser); + if (type_dependent_expression_p (m)) + m = build1 (IMPLICIT_CONV_EXPR, const_string_type_node, m); + else + m = perform_implicit_conversion_flags (const_string_type_node, m, + tf_warning_or_error, + LOOKUP_NORMAL); + } + else + { + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree val = cp_lexer_peek_token (parser->lexer)->u.value; + const char *q = IDENTIFIER_POINTER (val); + + if (!strcmp (q, args[idx])) + n = 0; + else if (!strcmp (q, args[idx + 1])) + n = 1; + } + if (n == -1) + { + error_at (cp_lexer_peek_token (parser->lexer)->location, + "expected %qs or %qs", args[idx], args[idx + 1]); + bad = true; + switch (cp_lexer_peek_token (parser->lexer)->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + case CPP_CLOSE_PAREN: + break; + default: + if (cp_lexer_nth_token_is (parser->lexer, 2, + CPP_CLOSE_PAREN)) + cp_lexer_consume_token (parser->lexer); + break; + } + } + else + cp_lexer_consume_token (parser->lexer); + } + + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/ + true); + + if (v == NULL) + { + if (message) + { + error_at (cloc, "too many %qs clauses", p); + bad = true; + } + else + message = m; + } + else if (n != -1) + { + if (*v != -1) + { + error_at (cloc, "too many %qs clauses", p); + bad = true; + } + else + *v = n; + } + } + else + bad = true; + } + cp_parser_require_pragma_eol (parser, pragma_tok); + if (bad) + return true; + + if (at_compilation == -1) + at_compilation = 1; + if (severity_fatal == -1) + severity_fatal = 1; + if (!at_compilation) + { + if (context != pragma_compound) + { + error_at (loc, "%<#pragma omp error%> with % clause " + "may only be used in compound statements"); + return true; + } + tree fndecl + = builtin_decl_explicit (severity_fatal ? BUILT_IN_GOMP_ERROR + : BUILT_IN_GOMP_WARNING); + if (!message) + message = build_zero_cst (const_string_type_node); + tree stmt = build_call_expr_loc (loc, fndecl, 2, message, + build_all_ones_cst (size_type_node)); + add_stmt (stmt); + return true; + } + + if (in_discarded_stmt) + return false; + + const char *msg = NULL; + if (message) + { + msg = c_getstr (fold_for_warn (message)); + if (msg == NULL) + msg = _(""); + } + if (msg) + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "% encountered: %s", msg); + else + emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0, + "% encountered"); + return false; +} + /* OpenMP 4.5: #pragma omp taskloop taskloop-clause[optseq] new-line for-loop @@ -46703,6 +46901,9 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) cp_parser_omp_nothing (parser, pragma_tok); return false; + case PRAGMA_OMP_ERROR: + return cp_parser_omp_error (parser, pragma_tok, context); + case PRAGMA_OMP_ORDERED: if (context != pragma_stmt && context != pragma_compound) goto bad_stmt; -- cgit v1.1 From 7c9e1645836d7746838acebb7018b1774490ab5c Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 21 Aug 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f50c36c..d496202 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2021-08-20 Jakub Jelinek + + * parser.c (cp_parser_handle_statement_omp_attributes): Determine if + PRAGMA_OMP_ERROR directive is C_OMP_DIR_STANDALONE. + (cp_parser_omp_error): New function. + (cp_parser_pragma): Handle PRAGMA_OMP_ERROR. + +2021-08-20 Jakub Jelinek + + * parser.c (cp_parser_omp_clause_depend_sink): Reject spurious + comma at the end of list. Don't parse closing paren here... + (cp_parser_omp_clause_depend): ... but here instead. + 2021-08-19 Patrick Palka PR c++/101803 -- cgit v1.1 From 3bc75533d1f87f0617be6c1af98804f9127ec637 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 23 Aug 2021 10:16:24 +0200 Subject: openmp: Add support for strict modifier on grainsize/num_tasks clauses With strict: modifier on these clauses, the standard is explicit about how many iterations (and which) each generated task of taskloop directive should contain. For num_tasks it actually matches what we were already implementing, but for grainsize it does not (and even violates the old rule - without strict it requires that the number of iterations (unspecified which exactly) handled by each generated task is >= grainsize argument and < 2 * grainsize argument, with strict: it requires that each generated task handles exactly == grainsize argument iterations, except for the generated task handling the last iteration which can handles <= grainsize iterations). The following patch implements it for C and C++. 2021-08-23 Jakub Jelinek gcc/ * tree.h (OMP_CLAUSE_GRAINSIZE_STRICT): Define. (OMP_CLAUSE_NUM_TASKS_STRICT): Define. * tree-pretty-print.c (dump_omp_clause) : Print strict: modifier. * omp-expand.c (expand_task_call): Use GOMP_TASK_FLAG_STRICT in iflags if either grainsize or num_tasks clause has the strict modifier. gcc/c/ * c-parser.c (c_parser_omp_clause_num_tasks, c_parser_omp_clause_grainsize): Parse the optional strict: modifier. gcc/cp/ * parser.c (cp_parser_omp_clause_num_tasks, cp_parser_omp_clause_grainsize): Parse the optional strict: modifier. include/ * gomp-constants.h (GOMP_TASK_FLAG_STRICT): Define. libgomp/ * taskloop.c (GOMP_taskloop): Handle GOMP_TASK_FLAG_STRICT. * testsuite/libgomp.c-c++-common/taskloop-4.c (main): Fix up comment. * testsuite/libgomp.c-c++-common/taskloop-5.c: New test. --- gcc/cp/parser.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 63c9503..a959c71 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -37237,7 +37237,10 @@ cp_parser_omp_clause_num_threads (cp_parser *parser, tree list, } /* OpenMP 4.5: - num_tasks ( expression ) */ + num_tasks ( expression ) + + OpenMP 5.1: + num_tasks ( strict : expression ) */ static tree cp_parser_omp_clause_num_tasks (cp_parser *parser, tree list, @@ -37249,6 +37252,19 @@ cp_parser_omp_clause_num_tasks (cp_parser *parser, tree list, if (!parens.require_open (parser)) return list; + bool strict = false; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + if (!strcmp (IDENTIFIER_POINTER (id), "strict")) + { + strict = true; + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + } + } + t = cp_parser_assignment_expression (parser); if (t == error_mark_node @@ -37262,13 +37278,17 @@ cp_parser_omp_clause_num_tasks (cp_parser *parser, tree list, c = build_omp_clause (location, OMP_CLAUSE_NUM_TASKS); OMP_CLAUSE_NUM_TASKS_EXPR (c) = t; + OMP_CLAUSE_NUM_TASKS_STRICT (c) = strict; OMP_CLAUSE_CHAIN (c) = list; return c; } /* OpenMP 4.5: - grainsize ( expression ) */ + grainsize ( expression ) + + OpenMP 5.1: + grainsize ( strict : expression ) */ static tree cp_parser_omp_clause_grainsize (cp_parser *parser, tree list, @@ -37280,6 +37300,19 @@ cp_parser_omp_clause_grainsize (cp_parser *parser, tree list, if (!parens.require_open (parser)) return list; + bool strict = false; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + if (!strcmp (IDENTIFIER_POINTER (id), "strict")) + { + strict = true; + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + } + } + t = cp_parser_assignment_expression (parser); if (t == error_mark_node @@ -37293,6 +37326,7 @@ cp_parser_omp_clause_grainsize (cp_parser *parser, tree list, c = build_omp_clause (location, OMP_CLAUSE_GRAINSIZE); OMP_CLAUSE_GRAINSIZE_EXPR (c) = t; + OMP_CLAUSE_GRAINSIZE_STRICT (c) = strict; OMP_CLAUSE_CHAIN (c) = list; return c; -- cgit v1.1 From 38b19c5b0805f9acfcf52430cebca025fc3cdea6 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 24 Aug 2021 00:17:00 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d496202..ddea2a2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2021-08-23 Jakub Jelinek + + * parser.c (cp_parser_omp_clause_num_tasks, + cp_parser_omp_clause_grainsize): Parse the optional strict: modifier. + 2021-08-20 Jakub Jelinek * parser.c (cp_parser_handle_statement_omp_attributes): Determine if -- cgit v1.1 From 1ab84eda5548119908c4e24c6ad953dd7c00a5b7 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 25 Aug 2021 22:35:21 +0200 Subject: c++: Fix up value initialization of structs with zero width bitfields [PR102019] The removal of remove_zero_width_bit_fields, in addition to triggering some ABI issues that need solving anyway (ABI incompatibility between C and C++) also resulted in UB inside of gcc, we now call build_zero_init which calls build_int_cst on an integral type with TYPE_PRECISION of 0. Fixed by ignoring the zero width bitfields. I understand build_value_init_noctor wants to initialize to 0 even unnamed bitfields (of non-zero width), at least until we have some CONSTRUCTOR flag that says that even all the padding bits should be cleared. 2021-08-25 Jakub Jelinek PR c++/102019 * init.c (build_value_init_noctor): Ignore unnamed zero-width bitfields. --- gcc/cp/init.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 229c84e..1426f9a 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -427,6 +427,11 @@ build_value_init_noctor (tree type, tsubst_flags_t complain) == NULL_TREE)) continue; + /* Ignore unnamed zero-width bitfields. */ + if (DECL_UNNAMED_BIT_FIELD (field) + && integer_zerop (DECL_SIZE (field))) + continue; + /* We could skip vfields and fields of types with user-defined constructors, but I think that won't improve performance at all; it should be simpler in general just -- cgit v1.1 From 971df602e0a798fe9c805c3105f4ac80d638a12b Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Mon, 9 Aug 2021 18:33:17 -0700 Subject: Fix PR c++/66590: incorrect warning "reaches end of non-void function" for switch So the problem here is there is code in the C++ front-end not to add a break statement (to the IR) if the previous block does not fall through. The problem is the code which does the check to see if the block may fallthrough does not check a CLEANUP_STMT; it assumes it is always fall through. Anyways this adds the code for the case of a CLEANUP_STMT that is only for !CLEANUP_EH_ONLY (the try/finally case). OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. gcc/cp/ChangeLog: PR c++/66590 * cp-objcp-common.c (cxx_block_may_fallthru): Handle CLEANUP_STMT for the case which will be try/finally. gcc/testsuite/ChangeLog: PR c++/66590 * g++.dg/warn/Wreturn-5.C: New test. --- gcc/cp/cp-objcp-common.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 98fd962..28f2d7b 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -317,6 +317,15 @@ cxx_block_may_fallthru (const_tree stmt) return true; return block_may_fallthru (ELSE_CLAUSE (stmt)); + case CLEANUP_STMT: + /* Just handle the try/finally cases. */ + if (!CLEANUP_EH_ONLY (stmt)) + { + return (block_may_fallthru (CLEANUP_BODY (stmt)) + && block_may_fallthru (CLEANUP_EXPR (stmt))); + } + return true; + default: return c_block_may_fallthru (stmt); } -- cgit v1.1 From 85d77ac4745c6263520c8fe66c0dfced8404003f Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 26 Aug 2021 00:17:03 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ddea2a2..0b92ee4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2021-08-25 Andrew Pinski + + PR c++/66590 + * cp-objcp-common.c (cxx_block_may_fallthru): Handle + CLEANUP_STMT for the case which will be try/finally. + +2021-08-25 Jakub Jelinek + + PR c++/102019 + * init.c (build_value_init_noctor): Ignore unnamed zero-width + bitfields. + 2021-08-23 Jakub Jelinek * parser.c (cp_parser_omp_clause_num_tasks, -- cgit v1.1 From 771fd4aef999903cb928bb89f730c61a8af6e4f8 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 27 Aug 2021 10:00:49 -0400 Subject: c++: Set type on dependent ARROW_EXPR Even if the operand of -> has dependent type, if it's a pointer we know that the result will be the target type of that pointer. This should avoid some unnecessary TYPEOF_EXPR when looking up a name after ->. gcc/cp/ChangeLog: * typeck2.c (build_x_arrow): Do set TREE_TYPE when operand is a dependent pointer. --- gcc/cp/typeck2.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index dcfdff2..5e2c23c 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1913,11 +1913,17 @@ build_x_arrow (location_t loc, tree expr, tsubst_flags_t complain) if (processing_template_decl) { - if (type && TYPE_PTR_P (type) - && !dependent_scope_p (TREE_TYPE (type))) + tree ttype = NULL_TREE; + if (type && TYPE_PTR_P (type)) + ttype = TREE_TYPE (type); + if (ttype && !dependent_scope_p (ttype)) /* Pointer to current instantiation, don't treat as dependent. */; else if (type_dependent_expression_p (expr)) - return build_min_nt_loc (loc, ARROW_EXPR, expr); + { + expr = build_min_nt_loc (loc, ARROW_EXPR, expr); + TREE_TYPE (expr) = ttype; + return expr; + } expr = build_non_dependent_expr (expr); } -- cgit v1.1 From 1e52538d2b430a26032d736079518ecad3bcca44 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 28 Aug 2021 00:16:42 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0b92ee4..81372f9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2021-08-27 Jason Merrill + + * typeck2.c (build_x_arrow): Do set TREE_TYPE when operand is + a dependent pointer. + 2021-08-25 Andrew Pinski PR c++/66590 -- cgit v1.1 From e18e56c76be35e6a799e07a01c24e0fff3eb1978 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 27 Aug 2021 17:28:28 -0400 Subject: c++: Add warning about missing 'requires' I noticed that concepts-lambda14.C had two useless requires-expressions: static_assert(requires { C; }); always succeeds, because C is always a valid expression for any type, regardless of whether C is satisfied for a particular type. Presumably the user means static_assert(requires { requires C; }); to make the C a nested-requirement. Of course, static_assert(C); is much simpler and means the same thing; this is more relevant in the middle of a longer requires-expression, such as the bug this warning found in cmcstl2: template META_CONCEPT input_iterator = input_or_output_iterator && readable && requires(I& i, const I& ci) { typename iterator_category_t; derived_from, input_iterator_tag>; i++; }; where 'requires' is missing before 'derived_from'. gcc/ChangeLog: * doc/invoke.texi: Document -Wmissing-requires. gcc/c-family/ChangeLog: * c.opt: Add -Wmissing-requires. gcc/cp/ChangeLog: * parser.c (cp_parser_simple_requirement): Warn about missing requires. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-lambda14.C: Add expected warnings. --- gcc/cp/parser.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a959c71..797e70b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -29911,6 +29911,25 @@ cp_parser_simple_requirement (cp_parser *parser) if (expr.get_location() == UNKNOWN_LOCATION) expr.set_location (start); + for (tree t = expr; ; ) + { + if (TREE_CODE (t) == TRUTH_ANDIF_EXPR + || TREE_CODE (t) == TRUTH_ORIF_EXPR) + { + t = TREE_OPERAND (t, 0); + continue; + } + if (concept_check_p (t)) + { + gcc_rich_location richloc (get_start (start)); + richloc.add_fixit_insert_before (start, "requires "); + warning_at (&richloc, OPT_Wmissing_requires, "testing " + "if a concept-id is a valid expression; add " + "% to check satisfaction"); + } + break; + } + return finish_simple_requirement (expr.get_location (), expr); } -- cgit v1.1 From a8de832470f78a40a0e2c8de866a471bf74bf0ab Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 30 Aug 2021 09:44:28 -0400 Subject: c++: fold function template args sooner [PR101460] As discussed in the PR, we were giving a lot of unnecessary errors for this testcase because we didn't try to do constant evaluation until convert_nontype_argument, which happens for each of the candidates. But when looking at a template-id as the function operand of a call, we can try to fold arguments before we get into overload resolution. PR c++/101460 gcc/cp/ChangeLog: * cp-tree.h (cxx_constant_value_sfinae): Declare. * constexpr.c (cxx_constant_value_sfinae): New. * pt.c (fold_targs_r, maybe_fold_fn_template_args): New. (tsubst_copy_and_build) [CALL_EXPR]: Call maybe_fold_fn_template_args. gcc/testsuite/ChangeLog: * g++.dg/template/explicit-args6.C: New test. --- gcc/cp/constexpr.c | 12 +++++++++++ gcc/cp/cp-tree.h | 1 + gcc/cp/pt.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index b9c0062..9606719 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -7458,6 +7458,18 @@ cxx_constant_value (tree t, tree decl) return cxx_eval_outermost_constant_expr (t, false, true, true, false, decl); } +/* As above, but respect SFINAE. */ + +tree +cxx_constant_value_sfinae (tree t, tsubst_flags_t complain) +{ + bool sfinae = !(complain & tf_error); + tree r = cxx_eval_outermost_constant_expr (t, sfinae, true, true); + if (sfinae && !TREE_CONSTANT (r)) + r = error_mark_node; + return r; +} + /* Like cxx_constant_value, but used for evaluation of constexpr destructors of constexpr variables. The actual initializer of DECL is not modified. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 75ee887..6a17937 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8266,6 +8266,7 @@ extern bool require_constant_expression (tree); extern bool require_rvalue_constant_expression (tree); extern bool require_potential_rvalue_constant_expression (tree); extern tree cxx_constant_value (tree, tree = NULL_TREE); +extern tree cxx_constant_value_sfinae (tree, tsubst_flags_t); extern void cxx_constant_dtor (tree, tree); extern tree cxx_constant_init (tree, tree = NULL_TREE); extern tree maybe_constant_value (tree, tree = NULL_TREE, bool = false); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 020a4bf..d7d0dce 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -19465,6 +19465,63 @@ out: return r; } +/* Subroutine of maybe_fold_fn_template_args. */ + +static bool +fold_targs_r (tree targs, tsubst_flags_t complain) +{ + int len = TREE_VEC_LENGTH (targs); + for (int i = 0; i < len; ++i) + { + tree &elt = TREE_VEC_ELT (targs, i); + if (!elt || TYPE_P (elt) + || TREE_CODE (elt) == TEMPLATE_DECL) + continue; + if (TREE_CODE (elt) == NONTYPE_ARGUMENT_PACK) + { + if (!fold_targs_r (ARGUMENT_PACK_ARGS (elt), complain)) + return false; + } + else if (/* We can only safely preevaluate scalar prvalues. */ + SCALAR_TYPE_P (TREE_TYPE (elt)) + && !glvalue_p (elt) + && !TREE_CONSTANT (elt)) + { + elt = cxx_constant_value_sfinae (elt, complain); + if (elt == error_mark_node) + return false; + } + } + + return true; +} + +/* Try to do constant evaluation of any explicit template arguments in FN + before overload resolution, to get any errors only once. Return true iff + we didn't have any problems folding. */ + +static bool +maybe_fold_fn_template_args (tree fn, tsubst_flags_t complain) +{ + if (processing_template_decl || fn == NULL_TREE) + return true; + if (fn == error_mark_node) + return false; + if (TREE_CODE (fn) == OFFSET_REF + || TREE_CODE (fn) == COMPONENT_REF) + fn = TREE_OPERAND (fn, 1); + if (BASELINK_P (fn)) + fn = BASELINK_FUNCTIONS (fn); + if (TREE_CODE (fn) != TEMPLATE_ID_EXPR) + return true; + tree targs = TREE_OPERAND (fn, 1); + if (targs == NULL_TREE) + return true; + if (targs == error_mark_node) + return false; + return fold_targs_r (targs, complain); +} + /* Like tsubst but deals with expressions and performs semantic analysis. FUNCTION_P is true if T is the "F" in "F (ARGS)" or "F (ARGS)". */ @@ -20343,6 +20400,9 @@ tsubst_copy_and_build (tree t, && !mark_used (function, complain) && !(complain & tf_error)) RETURN (error_mark_node); + if (!maybe_fold_fn_template_args (function, complain)) + return error_mark_node; + /* Put back tf_decltype for the actual call. */ complain |= decltype_flag; -- cgit v1.1 From 729f6881cfcc6df3c15a1dd4ebd45bc46bb8f3e9 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 28 Aug 2021 00:40:29 -0400 Subject: c++: preserve location through constexpr While working on the patch for PR101460, I noticed that we were losing the expression location when folding class prvalue expressions. The final patch doesn't fold class prvalues, but this still seems a worthwhile change. I don't add location wrappers for scalar prvalues because many callers are trying to fold them away. gcc/cp/ChangeLog: * constexpr.c (cxx_eval_outermost_constant_expr): Copy expr location to result. --- gcc/cp/constexpr.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 9606719..e78fdf0 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -7445,6 +7445,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, } } + /* Remember the original location if that wouldn't need a wrapper. */ + if (location_t loc = EXPR_LOCATION (t)) + if (CAN_HAVE_LOCATION_P (r)) + SET_EXPR_LOCATION (r, loc); + return r; } -- cgit v1.1 From 8960a29b18b830ff0490b7f52051903fba472e45 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sun, 29 Aug 2021 18:17:22 -0400 Subject: c++: limit instantiation with ill-formed class [PR96286] I noticed that after the static_assert failures in lwg3466.cc, we got various follow-on errors because we went ahead and tried to instantiate the promise member functions even after instantiating the class itself ran into problems. Interrupting instantiation of the class itself seems likely to cause error-recovery problems, but preventing instantiation of member functions seems strictly better for error-recovery. This doesn't fix any of the specific testcases in PR96286, but addresses part of that problem space. PR c++/96286 gcc/cp/ChangeLog: * cp-tree.h (struct lang_type): Add erroneous bit-field. (CLASSTYPE_ERRONEOUS): New. * pt.c (limit_bad_template_recursion): Check it. (instantiate_class_template_1): Set it. libstdc++-v3/ChangeLog: * testsuite/30_threads/promise/requirements/lwg3466.cc: Remove dg-prune-outputs. gcc/testsuite/ChangeLog: * g++.dg/template/access2.C: Split struct A. --- gcc/cp/cp-tree.h | 7 ++++++- gcc/cp/pt.c | 14 +++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6a17937..ce7ca53 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2336,6 +2336,7 @@ struct GTY(()) lang_type { unsigned has_constexpr_ctor : 1; unsigned unique_obj_representations : 1; unsigned unique_obj_representations_set : 1; + bool erroneous : 1; /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If @@ -2344,7 +2345,7 @@ struct GTY(()) lang_type { /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or remove a flag. */ - unsigned dummy : 5; + unsigned dummy : 4; tree primary_base; vec *vcall_indices; @@ -2660,6 +2661,10 @@ struct GTY(()) lang_type { /* Nonzero if a _DECL node requires us to output debug info for this class. */ #define CLASSTYPE_DEBUG_REQUESTED(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->debug_requested) + +/* True if we saw errors while instantiating this class. */ +#define CLASSTYPE_ERRONEOUS(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->erroneous) /* Additional macros for inheritance information. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d7d0dce..fcf3ac3 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10885,9 +10885,14 @@ limit_bad_template_recursion (tree decl) { struct tinst_level *lev = current_tinst_level; int errs = errorcount + sorrycount; - if (lev == NULL || errs == 0 || !neglectable_inst_p (decl)) + if (errs == 0 || !neglectable_inst_p (decl)) return false; + /* Avoid instantiating members of an ill-formed class. */ + if (DECL_CLASS_SCOPE_P (decl) + && CLASSTYPE_ERRONEOUS (DECL_CONTEXT (decl))) + return true; + for (; lev; lev = lev->next) if (neglectable_inst_p (lev->maybe_get_node ())) break; @@ -12212,6 +12217,13 @@ instantiate_class_template_1 (tree type) finish_struct_1 (type); TYPE_BEING_DEFINED (type) = 0; + /* Remember if instantiating this class ran into errors, so we can avoid + instantiating member functions in limit_bad_template_recursion. We set + this flag even if the problem was in another instantiation triggered by + this one, as that will likely also cause trouble for member functions. */ + if (errorcount + sorrycount > current_tinst_level->errors) + CLASSTYPE_ERRONEOUS (type) = true; + /* We don't instantiate default arguments for member functions. 14.7.1: The implicit instantiation of a class template specialization causes -- cgit v1.1 From 1e2f030b80cb650708b02086dbd5431cd231495f Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 31 Aug 2021 00:16:50 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 81372f9..87760a6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,30 @@ +2021-08-30 Jason Merrill + + PR c++/96286 + * cp-tree.h (struct lang_type): Add erroneous bit-field. + (CLASSTYPE_ERRONEOUS): New. + * pt.c (limit_bad_template_recursion): Check it. + (instantiate_class_template_1): Set it. + +2021-08-30 Jason Merrill + + * constexpr.c (cxx_eval_outermost_constant_expr): Copy + expr location to result. + +2021-08-30 Jason Merrill + + PR c++/101460 + * cp-tree.h (cxx_constant_value_sfinae): Declare. + * constexpr.c (cxx_constant_value_sfinae): New. + * pt.c (fold_targs_r, maybe_fold_fn_template_args): New. + (tsubst_copy_and_build) [CALL_EXPR]: Call + maybe_fold_fn_template_args. + +2021-08-30 Jason Merrill + + * parser.c (cp_parser_simple_requirement): Warn about missing + requires. + 2021-08-27 Jason Merrill * typeck2.c (build_x_arrow): Do set TREE_TYPE when operand is -- 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/parser.c | 42 +++++++++++++++++++++++++++++++++++++++++- gcc/cp/semantics.c | 9 +++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 797e70b..7dc4eae 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -39049,18 +39049,57 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) } /* OpenMP 4.0: - device ( expression ) */ + device ( expression ) + + OpenMP 5.0: + device ( [device-modifier :] integer-expression ) + + device-modifier: + ancestor | device_num */ static tree cp_parser_omp_clause_device (cp_parser *parser, tree list, location_t location) { tree t, c; + bool ancestor = false; matching_parens parens; if (!parens.require_open (parser)) return list; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + { + cp_token *tok = cp_lexer_peek_token (parser->lexer); + const char *p = IDENTIFIER_POINTER (tok->u.value); + if (strcmp ("ancestor", p) == 0) + { + ancestor = true; + + /* A requires directive with the reverse_offload clause must be + specified. */ + if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0) + { + error_at (tok->location, "% device modifier not " + "preceded by % directive " + "with % clause"); + cp_parser_skip_to_closing_parenthesis (parser, true, false, true); + return list; + } + } + else if (strcmp ("device_num", p) == 0) + ; + else + { + error_at (tok->location, "expected % or %"); + cp_parser_skip_to_closing_parenthesis (parser, true, false, true); + return list; + } + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + } + t = cp_parser_assignment_expression (parser); if (t == error_mark_node @@ -39075,6 +39114,7 @@ cp_parser_omp_clause_device (cp_parser *parser, tree list, c = build_omp_clause (location, OMP_CLAUSE_DEVICE); OMP_CLAUSE_DEVICE_ID (c) = t; OMP_CLAUSE_CHAIN (c) = list; + OMP_CLAUSE_DEVICE_ANCESTOR (c) = ancestor; return 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 9aeadd8c319d5d940fa4dc91a393fc2959d27719 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 30 Aug 2021 18:42:05 -0400 Subject: c++: Improve error recovery with constexpr [PR92193] The compiler tries to limit error cascades in limit_bad_template_recursion by avoiding triggering a new instantiation from one that has caused errors. We were exempting constexpr functions from this because they can be needed for constant evaluation, but as more and more functions get marked constexpr, this becomes an over-broad category. So as suggested on IRC, this patch only exempts functions that are needed for mandatory constant evaluation. As noted in the comment, this flag doesn't particularly need to use a bit in the FUNCTION_DECL, but there were still some free. PR c++/92193 gcc/cp/ChangeLog: * cp-tree.h (FNDECL_MANIFESTLY_CONST_EVALUATED): New. * constexpr.c (cxx_eval_call_expression): Set it. * pt.c (neglectable_inst_p): Check it. gcc/testsuite/ChangeLog: * g++.dg/diagnostic/static_assert4.C: New test. --- gcc/cp/constexpr.c | 2 ++ gcc/cp/cp-tree.h | 8 ++++++++ gcc/cp/pt.c | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index e78fdf0..8be88dc 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -2572,6 +2572,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, location_t save_loc = input_location; input_location = loc; ++function_depth; + if (ctx->manifestly_const_eval) + FNDECL_MANIFESTLY_CONST_EVALUATED (fun) = true; instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false); --function_depth; input_location = save_loc; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ce7ca53..f0a7bd2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -500,6 +500,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; FUNCTION_REF_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) OVL_LOOKUP_P (in OVERLOAD) LOOKUP_FOUND_P (in RECORD_TYPE, UNION_TYPE, ENUMERAL_TYPE, NAMESPACE_DECL) + FNDECL_MANIFESTLY_CONST_EVALUATED (in FUNCTION_DECL) 5: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR) @@ -4213,6 +4214,13 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define FNDECL_USED_AUTO(NODE) \ TREE_LANG_FLAG_2 (FUNCTION_DECL_CHECK (NODE)) +/* True if NODE is needed for a manifestly constant-evaluated expression. + This doesn't especially need to be a flag, since currently it's only + used for error recovery; if we run out of function flags it could move + to an attribute. */ +#define FNDECL_MANIFESTLY_CONST_EVALUATED(NODE) \ + TREE_LANG_FLAG_4 (FUNCTION_DECL_CHECK (NODE)) + /* True for artificial decls added for OpenMP privatized non-static data members. */ #define DECL_OMP_PRIVATIZED_MEMBER(NODE) \ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index fcf3ac3..72b22d8 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10873,7 +10873,8 @@ neglectable_inst_p (tree d) { return (d && DECL_P (d) && !undeduced_auto_decl (d) - && !(TREE_CODE (d) == FUNCTION_DECL ? DECL_DECLARED_CONSTEXPR_P (d) + && !(TREE_CODE (d) == FUNCTION_DECL + ? FNDECL_MANIFESTLY_CONST_EVALUATED (d) : decl_maybe_constant_var_p (d))); } -- cgit v1.1 From 17dc903ed36ea0b6189d66a36d36e0c5ab803a7b Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 27 Aug 2021 22:59:48 -0400 Subject: c++: use iloc_sentinel in another place Another place we can use iloc_sentinel instead of explicitly saving and restoring input_location. gcc/cp/ChangeLog: * constexpr.c (explain_invalid_constexpr_fn): Use iloc_sentinel. --- gcc/cp/constexpr.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 8be88dc..45adbab 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -942,7 +942,6 @@ explain_invalid_constexpr_fn (tree fun) { static hash_set *diagnosed; tree body; - location_t save_loc; /* Only diagnose defaulted functions, lambdas, or instantiations. */ if (!DECL_DEFAULTED_FN (fun) && !LAMBDA_TYPE_P (CP_DECL_CONTEXT (fun)) @@ -957,7 +956,7 @@ explain_invalid_constexpr_fn (tree fun) /* Already explained. */ return; - save_loc = input_location; + iloc_sentinel ils = input_location; if (!lambda_static_thunk_p (fun)) { /* Diagnostics should completely ignore the static thunk, so leave @@ -985,7 +984,6 @@ explain_invalid_constexpr_fn (tree fun) cx_check_missing_mem_inits (DECL_CONTEXT (fun), body, true); } } - input_location = save_loc; } /* Objects of this type represent calls to constexpr functions -- cgit v1.1 From e4d2305adf4e9d11e396c1c5e5ae6214340cbcc2 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Tue, 31 Aug 2021 11:15:21 -0600 Subject: Disable gcc_rich_location copying and assignment. gcc/cp/ChangeLog: * parser.c (cp_parser_selection_statement): Use direct initialization instead of copy. gcc/ChangeLog: * gcc-rich-location.h (gcc_rich_location): Make ctor explicit. libcpp/ChangeLog: * include/line-map.h (class rich_location): Disable copying and assignment. --- gcc/cp/parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7dc4eae..1e2a4b1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -12848,7 +12848,7 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, IF_STMT_CONSTEVAL_P (statement) = true; condition = finish_if_stmt_cond (boolean_false_node, statement); - gcc_rich_location richloc = tok->location; + gcc_rich_location richloc (tok->location); bool non_compound_stmt_p = false; if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)) { @@ -12876,7 +12876,7 @@ cp_parser_selection_statement (cp_parser* parser, bool *if_p, RID_ELSE)) { cp_token *else_tok = cp_lexer_peek_token (parser->lexer); - gcc_rich_location else_richloc = else_tok->location; + gcc_rich_location else_richloc (else_tok->location); guard_tinfo = get_token_indent_info (else_tok); /* Consume the `else' keyword. */ cp_lexer_consume_token (parser->lexer); -- cgit v1.1 From f1e7319956928712e8bf4893ebdfeeb6441099ee Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Tue, 31 Aug 2021 13:31:10 -0400 Subject: c++: check arity before deduction w/ explicit targs [PR12672] During overload resolution, when the arity of a function template clearly disagrees with the arity of the call, no specialization of the function template could yield a viable candidate. The deduction routine type_unification_real already notices this situation, but not before it substitutes explicit template arguments into the template, a step which could induce a hard error. Although it's necessary to perform this substitution first in order to check arity perfectly (since the substitution can e.g. expand a non-trailing parameter pack), in most cases we can determine ahead of time whether there's an arity disagreement without needing to perform deduction at all. To that end, this patch implements an (approximate) arity check in add_template_candidate_real that guards actual deduction. It's enabled only when there are explicit template arguments since that's when deduction can force otherwise avoidable template instantiations. (I experimented with enabling it unconditionally as an optimization, and observed some improvements to compile time of about 5% but also some slowdowns of about the same magnitude, so kept it conditional.) In passing, this adds a least_p parameter to arity_rejection for sake of consistent diagnostics with unify_arity. A couple of testcases needed to be adjusted so that deduction continues to occur as intended after this change. Except in unify6.C, where we were expecting foo to be ill-formed due to substitution forming a function type with an added 'const', but ISTM this is permitted by [dcl.fct]/7, so I changed the test accordingly. PR c++/12672 gcc/cp/ChangeLog: * call.c (rejection_reason::call_varargs_p): Rename this previously unused member to ... (rejection_reason::least_p): ... this. (arity_rejection): Add least_p parameter. (add_template_candidate_real): When there are explicit template arguments, check that the arity of the call agrees with the arity of the function before attempting deduction. (print_arity_information): Add least_p parameter. (print_z_candidate): Adjust call to print_arity_information. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/decltype29.C: Adjust. * g++.dg/template/error56.C: Adjust. * g++.old-deja/g++.pt/unify6.C: Adjust. * g++.dg/template/explicit-args7.C: New test. --- gcc/cp/call.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 10 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e4df72e..80e6121 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -455,8 +455,8 @@ struct rejection_reason { int expected; /* The actual number of arguments in the call. */ int actual; - /* Whether the call was a varargs call. */ - bool call_varargs_p; + /* Whether EXPECTED should be treated as a lower bound. */ + bool least_p; } arity; /* Information about an argument conversion mismatch. */ struct conversion_info conversion; @@ -628,12 +628,13 @@ alloc_rejection (enum rejection_reason_code code) } static struct rejection_reason * -arity_rejection (tree first_arg, int expected, int actual) +arity_rejection (tree first_arg, int expected, int actual, bool least_p = false) { struct rejection_reason *r = alloc_rejection (rr_arity); int adjust = first_arg != NULL_TREE; r->u.arity.expected = expected - adjust; r->u.arity.actual = actual - adjust; + r->u.arity.least_p = least_p; return r; } @@ -3452,6 +3453,44 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, } gcc_assert (ia == nargs_without_in_chrg); + if (!obj && explicit_targs) + { + /* Check that there's no obvious arity mismatch before proceeding with + deduction. This avoids substituting explicit template arguments + into the template (which could result in an error outside the + immediate context) when the resulting candidate would be unviable + anyway. */ + int min_arity = 0, max_arity = 0; + tree parms = TYPE_ARG_TYPES (TREE_TYPE (tmpl)); + parms = skip_artificial_parms_for (tmpl, parms); + for (; parms != void_list_node; parms = TREE_CHAIN (parms)) + { + if (!parms || PACK_EXPANSION_P (TREE_VALUE (parms))) + { + max_arity = -1; + break; + } + if (TREE_PURPOSE (parms)) + /* A parameter with a default argument. */ + ++max_arity; + else + ++min_arity, ++max_arity; + } + if (ia < (unsigned)min_arity) + { + /* Too few arguments. */ + reason = arity_rejection (NULL_TREE, min_arity, ia, + /*least_p=*/(max_arity == -1)); + goto fail; + } + else if (max_arity != -1 && ia > (unsigned)max_arity) + { + /* Too many arguments. */ + reason = arity_rejection (NULL_TREE, max_arity, ia); + goto fail; + } + } + errs = errorcount+sorrycount; if (!obj) convs = alloc_conversions (nargs); @@ -3725,12 +3764,19 @@ print_conversion_rejection (location_t loc, struct conversion_info *info, HAVE. */ static void -print_arity_information (location_t loc, unsigned int have, unsigned int want) -{ - inform_n (loc, want, - " candidate expects %d argument, %d provided", - " candidate expects %d arguments, %d provided", - want, have); +print_arity_information (location_t loc, unsigned int have, unsigned int want, + bool least_p) +{ + if (least_p) + inform_n (loc, want, + " candidate expects at least %d argument, %d provided", + " candidate expects at least %d arguments, %d provided", + want, have); + else + inform_n (loc, want, + " candidate expects %d argument, %d provided", + " candidate expects %d arguments, %d provided", + want, have); } /* Print information about one overload candidate CANDIDATE. MSGSTR @@ -3794,7 +3840,8 @@ print_z_candidate (location_t loc, const char *msgstr, { case rr_arity: print_arity_information (cloc, r->u.arity.actual, - r->u.arity.expected); + r->u.arity.expected, + r->u.arity.least_p); break; case rr_arg_conversion: print_conversion_rejection (cloc, &r->u.conversion, fn); -- cgit v1.1 From 9c6344c10de1c90015c68adfb880291af980b886 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 25 Aug 2021 15:10:21 -0400 Subject: c++: Various small fixes A copy-paste error, a couple of missed checks to guard undefined accesses, and we don't need to use type_uses_auto to extract the auto node we just built. gcc/cp/ChangeLog: * coroutines.cc (flatten_await_stmt): Fix copyo. * decl.c (reshape_init_class): Simplify. * module.cc (module_state::read_language): Add null check. * parser.c (build_range_temp): Avoid type_uses_auto. (cp_parser_class_specifier_1): Add null check. --- gcc/cp/coroutines.cc | 2 +- gcc/cp/decl.c | 3 +-- gcc/cp/module.cc | 2 +- gcc/cp/parser.c | 15 +++++++-------- 4 files changed, 10 insertions(+), 12 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 47c79e5..25269d9 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2905,7 +2905,7 @@ flatten_await_stmt (var_nest_node *n, hash_set *promoted, tree else_cl = COND_EXPR_ELSE (old_expr); if (!VOID_TYPE_P (TREE_TYPE (else_cl))) { - gcc_checking_assert (TREE_CODE (then_cl) != STATEMENT_LIST); + gcc_checking_assert (TREE_CODE (else_cl) != STATEMENT_LIST); else_cl = build2 (init_expr ? INIT_EXPR : MODIFY_EXPR, var_type, var, else_cl); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 3414cbd..e981ead 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6563,8 +6563,7 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p, continue_: if (base_binfo) { - BINFO_BASE_ITERATE (binfo, ++binfo_idx, base_binfo); - if (base_binfo) + if (BINFO_BASE_ITERATE (binfo, ++binfo_idx, base_binfo)) field = base_binfo; else field = next_initializable_field (TYPE_FIELDS (type)); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index ccbde29..4b2ad6f 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -17977,7 +17977,7 @@ module_state::read_language (bool outermost) function_depth++; /* Prevent unexpected GCs. */ - if (counts[MSC_entities] != entity_num) + if (ok && counts[MSC_entities] != entity_num) ok = false; if (ok && counts[MSC_entities] && !read_entities (counts[MSC_entities], diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1e2a4b1..d3c31be 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -13474,17 +13474,15 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, static tree build_range_temp (tree range_expr) { - tree range_type, range_temp; - /* Find out the type deduced by the declaration `auto &&__range = range_expr'. */ - range_type = cp_build_reference_type (make_auto (), true); - range_type = do_auto_deduction (range_type, range_expr, - type_uses_auto (range_type)); + tree auto_node = make_auto (); + tree range_type = cp_build_reference_type (auto_node, true); + range_type = do_auto_deduction (range_type, range_expr, auto_node); /* Create the __range variable. */ - range_temp = build_decl (input_location, VAR_DECL, for_range__identifier, - range_type); + tree range_temp = build_decl (input_location, VAR_DECL, + for_range__identifier, range_type); TREE_USED (range_temp) = 1; DECL_ARTIFICIAL (range_temp) = 1; @@ -25910,7 +25908,8 @@ cp_parser_class_specifier_1 (cp_parser* parser) so that maybe_instantiate_noexcept can tsubst the NOEXCEPT_EXPR in the pattern. */ for (tree i : DEFPARSE_INSTANTIATIONS (def_parse)) - DEFERRED_NOEXCEPT_PATTERN (TREE_PURPOSE (i)) = TREE_PURPOSE (spec); + DEFERRED_NOEXCEPT_PATTERN (TREE_PURPOSE (i)) + = spec ? TREE_PURPOSE (spec) : error_mark_node; /* Restore the state of local_variables_forbidden_p. */ parser->local_variables_forbidden_p = local_variables_forbidden_p; -- cgit v1.1 From 6d51ee4321605c704aa238d039b47bfcf59b1005 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 1 Sep 2021 00:16:58 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 87760a6..b443247 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,47 @@ +2021-08-31 Jason Merrill + + * coroutines.cc (flatten_await_stmt): Fix copyo. + * decl.c (reshape_init_class): Simplify. + * module.cc (module_state::read_language): Add null check. + * parser.c (build_range_temp): Avoid type_uses_auto. + (cp_parser_class_specifier_1): Add null check. + +2021-08-31 Patrick Palka + + PR c++/12672 + * call.c (rejection_reason::call_varargs_p): Rename this + previously unused member to ... + (rejection_reason::least_p): ... this. + (arity_rejection): Add least_p parameter. + (add_template_candidate_real): When there are explicit + template arguments, check that the arity of the call agrees with + the arity of the function before attempting deduction. + (print_arity_information): Add least_p parameter. + (print_z_candidate): Adjust call to print_arity_information. + +2021-08-31 Martin Sebor + + * parser.c (cp_parser_selection_statement): Use direct initialization + instead of copy. + +2021-08-31 Jason Merrill + + * constexpr.c (explain_invalid_constexpr_fn): Use iloc_sentinel. + +2021-08-31 Jason Merrill + + PR c++/92193 + * cp-tree.h (FNDECL_MANIFESTLY_CONST_EVALUATED): New. + * constexpr.c (cxx_eval_call_expression): Set it. + * pt.c (neglectable_inst_p): Check it. + +2021-08-31 Marcel Vollweiler + + * 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. + 2021-08-30 Jason Merrill PR c++/96286 -- cgit v1.1 From 8406ed9af2655479a9c8469d7acca2cf5784f5d6 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Wed, 3 Mar 2021 16:13:00 +0000 Subject: coroutines: No cleanups on goto statements. Minor cleanup, this is statement not an expression, we do not need to use finish_expr_stmt here. Signed-off-by: Iain Sandoe gcc/cp/ChangeLog: * coroutines.cc (await_statement_walker): Use build_stmt and add_stmt instead of build1 and finish_expr_stmt. --- gcc/cp/coroutines.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 25269d9..3bb33cc 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -3824,8 +3824,8 @@ await_statement_walker (tree *stmt, int *do_subtree, void *d) the parameter to return_value(). */ if (!maybe_await_stmt) maybe_await_stmt = tsi_stmt_ptr (tsi_last (ret_list)); - expr = build1_loc (loc, GOTO_EXPR, void_type_node, awpts->fs_label); - finish_expr_stmt (expr); + TREE_USED (awpts->fs_label) = 1; + add_stmt (build_stmt (loc, GOTO_EXPR, awpts->fs_label)); *stmt = pop_stmt_list (ret_list); /* Once this is complete, we will have processed subtrees. */ *do_subtree = 0; -- cgit v1.1 From 21b4d0ef543d68187d258415b51d0d6676af89fd Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Wed, 3 Mar 2021 16:14:24 +0000 Subject: coroutines : Add a missed begin/finish else clause to the codegen. Minor code-gen correction. Signed-off-by: Iain Sandoe gcc/cp/ChangeLog: * coroutines.cc (build_actor_fn): Add begin/finish clauses to the initial test in the actor function. --- gcc/cp/coroutines.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 3bb33cc..ceb3d3b 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2331,6 +2331,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, finish_switch_stmt (destroy_dispatcher); finish_then_clause (lsb_if); + begin_else_clause (lsb_if); tree dispatcher = begin_switch_stmt (); finish_switch_cond (rat, dispatcher); @@ -2368,6 +2369,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Insert the prototype dispatcher. */ finish_switch_stmt (dispatcher); + finish_else_clause (lsb_if); finish_if_stmt (lsb_if); -- cgit v1.1 From 8433baadec88e5f31fa141b6d78094e91256079d Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sun, 8 Nov 2020 09:04:07 +0000 Subject: C-family: Add attribute 'unavailable'. If an interface is marked 'deprecated' then, presumably, at some point it will be withdrawn and no longer available. The 'unavailable' attribute makes it possible to mark up interfaces to indicate this status. It is used quite extensively in some codebases where a single set of headers can be used to permit code generation for multiple system versions. From a configuration perspective, it also allows a compile test to determine that an interface is missing - rather than requiring a link test. The implementation follows the pattern of attribute deprecated, but produces an error (where deprecation produces a warning). This attribute has been implemented in clang for some years. Signed-off-by: Iain Sandoe gcc/c-family/ChangeLog: * c-attribs.c (handle_unavailable_attribute): New. gcc/c/ChangeLog: * c-decl.c (enum deprecated_states): Add unavailable state. (merge_decls): Copy unavailability. (quals_from_declspecs): Handle unavailable case. (start_decl): Amend the logic handling suppression of nested deprecation states to include unavailability. (smallest_type_quals_location): Amend comment. (grokdeclarator): Handle the unavailable deprecation state. (declspecs_add_type): Set TREE_UNAVAILABLE from the decl specs. * c-tree.h (struct c_declspecs): Add unavailable_p. * c-typeck.c (build_component_ref): Handle unavailability. (build_external_ref): Likewise. gcc/cp/ChangeLog: * call.c (build_over_call): Handle unavailable state in addition to deprecation. * class.c (type_build_ctor_call): Likewise. (type_build_dtor_call): Likewise. * cp-tree.h: Rename cp_warn_deprecated_use to cp_handle_deprecated_or_unavailable. * decl.c (duplicate_decls): Merge unavailability. (grokdeclarator): Handle unavailability in addition to deprecation. (type_is_unavailable): New. (grokparms): Handle unavailability in addition to deprecation. * decl.h (enum deprecated_states): Add UNAVAILABLE_DEPRECATED_SUPPRESS. * decl2.c (cplus_decl_attributes): Propagate unavailability to templates. (cp_warn_deprecated_use): Rename to ... (cp_handle_deprecated_or_unavailable): ... this and amend to handle the unavailable case. It remains a warning in the case of deprecation but becomes an error in the case of unavailability. (cp_warn_deprecated_use_scopes): Handle unavailability. (mark_used): Likewise. * parser.c (cp_parser_template_name): Likewise. (cp_parser_template_argument): Likewise. (cp_parser_parameter_declaration_list): Likewise. * typeck.c (build_class_member_access_expr): Likewise. (finish_class_member_access_expr): Likewise. * typeck2.c (build_functional_cast_1): Likewise. gcc/ChangeLog: * doc/extend.texi: Document unavailable attribute. * print-tree.c (print_node): Handle unavailable attribute. * tree-core.h (struct tree_base): Add a bit to carry unavailability. * tree.c (error_unavailable_use): New. * tree.h (TREE_UNAVAILABLE): New. (error_unavailable_use): New. gcc/objc/ChangeLog: * objc-act.c (objc_add_property_declaration): Register unavailable attribute. (maybe_make_artificial_property_decl): Set available. (objc_maybe_build_component_ref): Generalise to the method prototype to count availability. (objc_build_class_component_ref): Likewise. (build_private_template): Likewise. (objc_decl_method_attributes): Handle unavailable attribute. (lookup_method_in_hash_lists): Amend comments. (objc_finish_message_expr): Handle unavailability in addition to deprecation. (start_class): Likewise. (finish_class): Likewise. (lookup_protocol): Likewise. (objc_declare_protocol): Likewise. (start_protocol): Register unavailable attribute. (really_start_method): Likewise. (objc_gimplify_property_ref): Emit error on encountering an unavailable entity (and a warning for a deprecated one). gcc/testsuite/ChangeLog: * g++.dg/ext/attr-unavailable-1.C: New test. * g++.dg/ext/attr-unavailable-2.C: New test. * g++.dg/ext/attr-unavailable-3.C: New test. * g++.dg/ext/attr-unavailable-4.C: New test. * g++.dg/ext/attr-unavailable-5.C: New test. * g++.dg/ext/attr-unavailable-6.C: New test. * g++.dg/ext/attr-unavailable-7.C: New test. * g++.dg/ext/attr-unavailable-8.C: New test. * g++.dg/ext/attr-unavailable-9.C: New test. * gcc.dg/attr-unavailable-1.c: New test. * gcc.dg/attr-unavailable-2.c: New test. * gcc.dg/attr-unavailable-3.c: New test. * gcc.dg/attr-unavailable-4.c: New test. * gcc.dg/attr-unavailable-5.c: New test. * gcc.dg/attr-unavailable-6.c: New test. * obj-c++.dg/attributes/method-unavailable-1.mm: New test. * obj-c++.dg/attributes/method-unavailable-2.mm: New test. * obj-c++.dg/attributes/method-unavailable-3.mm: New test. * obj-c++.dg/property/at-property-unavailable-1.mm: New test. * obj-c++.dg/property/at-property-unavailable-2.mm: New test. * obj-c++.dg/property/dotsyntax-unavailable-1.mm: New test. * objc.dg/attributes/method-unavailable-1.m: New test. * objc.dg/attributes/method-unavailable-2.m: New test. * objc.dg/attributes/method-unavailable-3.m: New test. * objc.dg/property/at-property-unavailable-1.m: New test. * objc.dg/property/at-property-unavailable-2.m: New test. * objc.dg/property/dotsyntax-unavailable-1.m: New test. --- gcc/cp/call.c | 4 ++-- gcc/cp/class.c | 2 ++ gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++------ gcc/cp/decl.h | 3 ++- gcc/cp/decl2.c | 58 +++++++++++++++++++++++++++++++++++++++++++------ gcc/cp/parser.c | 32 +++++++++++++++++---------- gcc/cp/typeck.c | 9 ++++++-- gcc/cp/typeck2.c | 2 +- 9 files changed, 146 insertions(+), 32 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 80e6121..7bbf134 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -9506,7 +9506,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) already_used = true; } else - cp_warn_deprecated_use (fn, complain); + cp_handle_deprecated_or_unavailable (fn, complain); if (eliding_temp && DECL_BASE_CONSTRUCTOR_P (fn) && !make_base_init_ok (arg)) @@ -9580,7 +9580,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) suppress_warning (val, OPT_Wunused); } - cp_warn_deprecated_use (fn, complain); + cp_handle_deprecated_or_unavailable (fn, complain); return val; } diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 7138e30..17876c7 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -5719,6 +5719,7 @@ type_build_ctor_call (tree t) tree fn = *iter; if (!DECL_ARTIFICIAL (fn) || TREE_DEPRECATED (fn) + || TREE_UNAVAILABLE (fn) || DECL_DELETED_FN (fn)) return true; } @@ -5747,6 +5748,7 @@ type_build_dtor_call (tree t) tree fn = *iter; if (!DECL_ARTIFICIAL (fn) || TREE_DEPRECATED (fn) + || TREE_UNAVAILABLE (fn) || DECL_DELETED_FN (fn)) return true; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f0a7bd2..435f32b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6549,7 +6549,7 @@ extern void validate_conversion_obstack (void); extern void mark_versions_used (tree); extern int unsafe_return_slot_p (tree); extern bool make_safe_copy_elision (tree, tree); -extern bool cp_warn_deprecated_use (tree, tsubst_flags_t = tf_warning_or_error); +extern bool cp_handle_deprecated_or_unavailable (tree, tsubst_flags_t = tf_warning_or_error); extern void cp_warn_deprecated_use_scopes (tree); extern tree get_function_version_dispatcher (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index e981ead..146979b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2418,6 +2418,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (TREE_DEPRECATED (newdecl)) TREE_DEPRECATED (olddecl) = 1; + /* Merge unavailability. */ + if (TREE_UNAVAILABLE (newdecl)) + TREE_UNAVAILABLE (olddecl) = 1; + /* Preserve function specific target and optimization options */ if (TREE_CODE (newdecl) == FUNCTION_DECL) { @@ -11757,20 +11761,24 @@ grokdeclarator (const cp_declarator *declarator, if (attrlist && *attrlist == error_mark_node) *attrlist = NULL_TREE; - /* An object declared as __attribute__((deprecated)) suppresses - warnings of uses of other deprecated items. */ + /* An object declared as __attribute__((unavailable)) suppresses + any reports of being declared with unavailable or deprecated + items. An object declared as __attribute__((deprecated)) + suppresses warnings of uses of other deprecated items. */ auto ds = make_temp_override (deprecated_state); - if (attrlist && lookup_attribute ("deprecated", *attrlist)) + if (attrlist && lookup_attribute ("unavailable", *attrlist)) + deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS; + else if (attrlist && lookup_attribute ("deprecated", *attrlist)) deprecated_state = DEPRECATED_SUPPRESS; - cp_warn_deprecated_use (type); + cp_handle_deprecated_or_unavailable (type); if (type && TREE_CODE (type) == TYPE_DECL) { cp_warn_deprecated_use_scopes (CP_DECL_CONTEXT (type)); typedef_decl = type; type = TREE_TYPE (typedef_decl); if (DECL_ARTIFICIAL (typedef_decl)) - cp_warn_deprecated_use (type); + cp_handle_deprecated_or_unavailable (type); } /* No type at all: default to `int', and set DEFAULTED_INT because it was not a user-defined typedef. */ @@ -14417,6 +14425,43 @@ type_is_deprecated (tree type) return NULL_TREE; } +/* Returns an unavailable type used within TYPE, or NULL_TREE if none. */ + +static tree +type_is_unavailable (tree type) +{ + enum tree_code code; + if (TREE_UNAVAILABLE (type)) + return type; + if (TYPE_NAME (type)) + { + if (TREE_UNAVAILABLE (TYPE_NAME (type))) + return type; + else + { + cp_warn_deprecated_use_scopes (CP_DECL_CONTEXT (TYPE_NAME (type))); + return NULL_TREE; + } + } + + /* Do warn about using typedefs to a deprecated class. */ + if (OVERLOAD_TYPE_P (type) && type != TYPE_MAIN_VARIANT (type)) + return type_is_deprecated (TYPE_MAIN_VARIANT (type)); + + code = TREE_CODE (type); + + if (code == POINTER_TYPE || code == REFERENCE_TYPE + || code == OFFSET_TYPE || code == FUNCTION_TYPE + || code == METHOD_TYPE || code == ARRAY_TYPE) + return type_is_unavailable (TREE_TYPE (type)); + + if (TYPE_PTRMEMFUNC_P (type)) + return type_is_unavailable + (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type)))); + + return NULL_TREE; +} + /* Decode the list of parameter types for a function type. Given the list of things declared inside the parens, return a list of types. @@ -14476,11 +14521,18 @@ grokparms (tree parmlist, tree *parms) if (type != error_mark_node) { - if (deprecated_state != DEPRECATED_SUPPRESS) + if (deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) + { + tree unavailtype = type_is_unavailable (type); + if (unavailtype) + cp_handle_deprecated_or_unavailable (unavailtype); + } + if (deprecated_state != DEPRECATED_SUPPRESS + && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) { tree deptype = type_is_deprecated (type); if (deptype) - cp_warn_deprecated_use (deptype); + cp_handle_deprecated_or_unavailable (deptype); } /* [dcl.fct] "A parameter with volatile-qualified type is diff --git a/gcc/cp/decl.h b/gcc/cp/decl.h index 387d807..4a9b399 100644 --- a/gcc/cp/decl.h +++ b/gcc/cp/decl.h @@ -44,7 +44,8 @@ extern void name_unnamed_type (tree, tree); enum deprecated_states { DEPRECATED_NORMAL, - DEPRECATED_SUPPRESS + DEPRECATED_SUPPRESS, + UNAVAILABLE_DEPRECATED_SUPPRESS }; extern enum deprecated_states deprecated_state; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 0c9d2f4..107edca 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1635,6 +1635,17 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) if (*decl == pattern) TREE_DEPRECATED (tmpl) = true; } + + /* Likewise, propagate unavailability out to the template. */ + if (TREE_UNAVAILABLE (*decl)) + if (tree ti = get_template_info (*decl)) + { + tree tmpl = TI_TEMPLATE (ti); + tree pattern = (TYPE_P (*decl) ? TREE_TYPE (tmpl) + : DECL_TEMPLATE_RESULT (tmpl)); + if (*decl == pattern) + TREE_UNAVAILABLE (tmpl) = true; + } } /* Walks through the namespace- or function-scope anonymous union @@ -5498,14 +5509,47 @@ maybe_instantiate_decl (tree decl) } } -/* Maybe warn if DECL is deprecated, subject to COMPLAIN. Returns whether or - not a warning was emitted. */ +/* Error if the DECL is unavailable (unless this is currently suppressed). + Maybe warn if DECL is deprecated, subject to COMPLAIN. Returns true if + an error or warning was emitted. */ bool -cp_warn_deprecated_use (tree decl, tsubst_flags_t complain) +cp_handle_deprecated_or_unavailable (tree decl, tsubst_flags_t complain) { - if (!(complain & tf_warning) || !decl - || deprecated_state == DEPRECATED_SUPPRESS) + if (!decl) + return false; + + if ((complain & tf_error) + && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) + { + if (TREE_UNAVAILABLE (decl)) + { + error_unavailable_use (decl, NULL_TREE); + return true; + } + else + { + /* Perhaps this is an unavailable typedef. */ + if (TYPE_P (decl) + && TYPE_NAME (decl) + && TREE_UNAVAILABLE (TYPE_NAME (decl))) + { + decl = TYPE_NAME (decl); + /* Don't error within members of a unavailable type. */ + if (TYPE_P (decl) + && currently_open_class (decl)) + return false; + + error_unavailable_use (decl, NULL_TREE); + return true; + } + } + /* Carry on to consider deprecatedness. */ + } + + if (!(complain & tf_warning) + || deprecated_state == DEPRECATED_SUPPRESS + || deprecated_state == UNAVAILABLE_DEPRECATED_SUPPRESS) return false; if (!TREE_DEPRECATED (decl)) @@ -5565,7 +5609,7 @@ cp_warn_deprecated_use_scopes (tree scope) && scope != global_namespace) { if ((TREE_CODE (scope) == NAMESPACE_DECL || OVERLOAD_TYPE_P (scope)) - && cp_warn_deprecated_use (scope)) + && cp_handle_deprecated_or_unavailable (scope)) return; if (TYPE_P (scope)) scope = CP_TYPE_CONTEXT (scope); @@ -5677,7 +5721,7 @@ mark_used (tree decl, tsubst_flags_t complain) TREE_USED (decl) = true; } - cp_warn_deprecated_use (decl, complain); + cp_handle_deprecated_or_unavailable (decl, complain); /* We can only check DECL_ODR_USED on variables or functions with DECL_LANG_SPECIFIC set, and these are also the only decls that we diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d3c31be..ea71f9c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18428,18 +18428,26 @@ cp_parser_template_name (cp_parser* parser, /* If DECL is a template, then the name was a template-name. */ if (TREE_CODE (decl) == TEMPLATE_DECL) { - if (TREE_DEPRECATED (decl) - && deprecated_state != DEPRECATED_SUPPRESS) + if ((TREE_DEPRECATED (decl) || TREE_UNAVAILABLE (decl)) + && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) { tree d = DECL_TEMPLATE_RESULT (decl); tree attr; if (TREE_CODE (d) == TYPE_DECL) - attr = lookup_attribute ("deprecated", - TYPE_ATTRIBUTES (TREE_TYPE (d))); + attr = TYPE_ATTRIBUTES (TREE_TYPE (d)); else - attr = lookup_attribute ("deprecated", - DECL_ATTRIBUTES (d)); - warn_deprecated_use (decl, attr); + attr = DECL_ATTRIBUTES (d); + if (TREE_UNAVAILABLE (decl)) + { + attr = lookup_attribute ("unavailable", attr); + error_unavailable_use (decl, attr); + } + else if (TREE_DEPRECATED (decl) + && deprecated_state != DEPRECATED_SUPPRESS) + { + attr = lookup_attribute ("deprecated", attr); + warn_deprecated_use (decl, attr); + } } } else @@ -18690,7 +18698,9 @@ cp_parser_template_argument (cp_parser* parser) } if (cp_parser_parse_definitely (parser)) { - if (TREE_DEPRECATED (argument)) + if (TREE_UNAVAILABLE (argument)) + error_unavailable_use (argument, NULL_TREE); + else if (TREE_DEPRECATED (argument)) warn_deprecated_use (argument, NULL_TREE); return argument; } @@ -24351,9 +24361,9 @@ cp_parser_parameter_declaration_list (cp_parser* parser, cp_parser_flags flags) /*template_parm_p=*/false, &parenthesized_p); - /* We don't know yet if the enclosing context is deprecated, so wait - and warn in grokparms if appropriate. */ - deprecated_state = DEPRECATED_SUPPRESS; + /* We don't know yet if the enclosing context is unavailable or deprecated, + so wait and deal with it in grokparms if appropriate. */ + deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS; if (parameter && !cp_parser_error_occurred (parser)) { diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index a46c6d2..cc61b50 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2709,7 +2709,10 @@ build_class_member_access_expr (cp_expr object, tree member, member_scope = DECL_CLASS_CONTEXT (member); if (!mark_used (member, complain) && !(complain & tf_error)) return error_mark_node; - if (TREE_DEPRECATED (member)) + + if (TREE_UNAVAILABLE (member)) + error_unavailable_use (member, NULL_TREE); + else if (TREE_DEPRECATED (member)) warn_deprecated_use (member, NULL_TREE); } else @@ -3424,7 +3427,9 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p, } } - if (TREE_DEPRECATED (member)) + if (TREE_UNAVAILABLE (member)) + error_unavailable_use (member, NULL_TREE); + else if (TREE_DEPRECATED (member)) warn_deprecated_use (member, NULL_TREE); if (template_p) diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 5e2c23c..f78dbf2 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -2163,7 +2163,7 @@ build_functional_cast_1 (location_t loc, tree exp, tree parms, type = TREE_TYPE (exp); if (DECL_ARTIFICIAL (exp)) - cp_warn_deprecated_use (type); + cp_handle_deprecated_or_unavailable (type); } else type = exp; -- cgit v1.1 From e11c6046f9c8bc891a67f37f0260ef4ece482f5d Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 2 Sep 2021 00:16:59 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b443247..d969b31 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,42 @@ +2021-09-01 Iain Sandoe + + * call.c (build_over_call): Handle unavailable state in addition to + deprecation. + * class.c (type_build_ctor_call): Likewise. + (type_build_dtor_call): Likewise. + * cp-tree.h: Rename cp_warn_deprecated_use to + cp_handle_deprecated_or_unavailable. + * decl.c (duplicate_decls): Merge unavailability. + (grokdeclarator): Handle unavailability in addition to deprecation. + (type_is_unavailable): New. + (grokparms): Handle unavailability in addition to deprecation. + * decl.h (enum deprecated_states): Add + UNAVAILABLE_DEPRECATED_SUPPRESS. + * decl2.c (cplus_decl_attributes): Propagate unavailability to + templates. + (cp_warn_deprecated_use): Rename to ... + (cp_handle_deprecated_or_unavailable): ... this and amend to handle + the unavailable case. It remains a warning in the case of deprecation + but becomes an error in the case of unavailability. + (cp_warn_deprecated_use_scopes): Handle unavailability. + (mark_used): Likewise. + * parser.c (cp_parser_template_name): Likewise. + (cp_parser_template_argument): Likewise. + (cp_parser_parameter_declaration_list): Likewise. + * typeck.c (build_class_member_access_expr): Likewise. + (finish_class_member_access_expr): Likewise. + * typeck2.c (build_functional_cast_1): Likewise. + +2021-09-01 Iain Sandoe + + * coroutines.cc (build_actor_fn): Add begin/finish clauses + to the initial test in the actor function. + +2021-09-01 Iain Sandoe + + * coroutines.cc (await_statement_walker): Use build_stmt and + add_stmt instead of build1 and finish_expr_stmt. + 2021-08-31 Jason Merrill * coroutines.cc (flatten_await_stmt): Fix copyo. -- cgit v1.1 From e902136b310ee17d4b49eb42d9d5e487d5dcf4a1 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 3 Sep 2021 09:46:32 +0200 Subject: c++, abi: Set DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD on C++ zero width bitfields [PR102024] The removal of remove_zero_width_bitfields function and its call from C++ FE layout_class_type (which I've done in the P0466R5 layout-compatible helper intrinsics patch, so that the FE can actually determine what is and isn't layout-compatible according to the spec) unfortunately changed the ABI on various platforms. The C FE has been keeping zero-width bitfields in the types, while the C++ FE has been removing them after structure layout, so in various cases when passing such structures in registers we had different ABI between C and C++. While both the C and C++ FE had some code to remove zero width bitfields after structure layout, in both FEs it was buggy and didn't really remove any. In the C FE that code has been removed later on, while in the C++ FE for GCC 4.5 in PR42217 it has been actually fixed, so the C++ FE started to remove those bitfields. The following patch doesn't change anything ABI-wise, but allows the targets to decide what to do, emit -Wpsabi warnings etc. Non-C zero width bitfields will be seen by the backends as normal zero width bitfields, C++ zero width bitfields that used to be previously removed will have DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD flag set. I've reused the DECL_FIELD_ABI_IGNORED flag which is only used on non-bitfield FIELD_DECLs right now, but the macros now check DECL_BIT_FIELD flag. Each backend can then decide what it wants, whether it wants to keep different ABI between C and C++ as in GCC 11 and older (i.e. incompatible with G++ <= 4.4, compatible with G++ 4.5 .. 11), for that it would ignore for the aggregate passing/returning decisions all DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD FIELD_DECLs), whether it wants to never ignore zero width bitfields (no changes needed for that case, except perhaps -Wpsabi warning should be added and for that DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD can be tested), or whether it wants to always ignore zero width bitfields (I think e.g. riscv in GCC 10+ does that). All this patch does is set the flag which the backends can then use. 2021-09-03 Jakub Jelinek PR target/102024 gcc/ * tree.h (DECL_FIELD_ABI_IGNORED): Changed into rvalue only macro that is false if DECL_BIT_FIELD. (SET_DECL_FIELD_ABI_IGNORED, DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD, SET_DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD): Define. * tree-streamer-out.c (pack_ts_decl_common_value_fields): For DECL_BIT_FIELD stream DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD instead of DECL_FIELD_ABI_IGNORED. * tree-streamer-in.c (unpack_ts_decl_common_value_fields): Use SET_DECL_FIELD_ABI_IGNORED instead of writing to DECL_FIELD_ABI_IGNORED and for DECL_BIT_FIELD use SET_DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD instead. * lto-streamer-out.c (hash_tree): For DECL_BIT_FIELD hash DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD instead of DECL_FIELD_ABI_IGNORED. gcc/cp/ * class.c (build_base_field): Use SET_DECL_FIELD_ABI_IGNORED instead of writing to DECL_FIELD_ABI_IGNORED. (layout_class_type): Likewise. In the place where zero-width bitfields used to be removed, use SET_DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD on those fields instead. gcc/lto/ * lto-common.c (compare_tree_sccs_1): Also compare DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD values. --- gcc/cp/class.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 17876c7..fe225c6 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4634,7 +4634,7 @@ build_base_field (record_layout_info rli, tree binfo, tree access, DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo); DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node; SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT); - DECL_FIELD_ABI_IGNORED (decl) = 1; + SET_DECL_FIELD_ABI_IGNORED (decl, 1); } /* An empty virtual base causes a class to be non-empty @@ -6658,7 +6658,7 @@ layout_class_type (tree t, tree *virtuals_p) } else if (might_overlap && is_empty_class (type)) { - DECL_FIELD_ABI_IGNORED (field) = 1; + SET_DECL_FIELD_ABI_IGNORED (field, 1); layout_empty_base_or_field (rli, field, empty_base_offsets); } else @@ -6746,6 +6746,23 @@ layout_class_type (tree t, tree *virtuals_p) normalize_rli (rli); } + /* We used to remove zero width bitfields at this point since PR42217, + while the C FE never did that. That caused ABI differences on various + targets. Set the DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD flag on them + instead, so that the backends can emit -Wpsabi warnings in the cases + where the ABI changed. */ + for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL + && DECL_C_BIT_FIELD (field) + /* We should not be confused by the fact that grokbitfield + temporarily sets the width of the bit field into + DECL_BIT_FIELD_REPRESENTATIVE (field). + check_bitfield_decl eventually sets DECL_SIZE (field) + to that width. */ + && (DECL_SIZE (field) == NULL_TREE + || integer_zerop (DECL_SIZE (field)))) + SET_DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD (field, 1); + if (CLASSTYPE_NON_LAYOUT_POD_P (t) || CLASSTYPE_EMPTY_P (t)) { /* T needs a different layout as a base (eliding virtual bases -- cgit v1.1 From 5ec4990bc777dd191b86aee6156be3f60cf9de24 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 2 Sep 2021 17:42:32 -0400 Subject: c++: Avoid bogus -Wunused with recent change My change to make limit_bad_template_recursion avoid instantiating members of erroneous classes produced a bogus "used but not defined" warning for 23_containers/unordered_set/instantiation_neg.cc; it's not defined because we decided not to instantiate it. So we need to suppress that warning. gcc/cp/ChangeLog: * pt.c (limit_bad_template_recursion): Suppress -Wunused for decls we decide not to instantiate. --- gcc/cp/pt.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 72b22d8..1b81501 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10890,15 +10890,27 @@ limit_bad_template_recursion (tree decl) return false; /* Avoid instantiating members of an ill-formed class. */ - if (DECL_CLASS_SCOPE_P (decl) - && CLASSTYPE_ERRONEOUS (DECL_CONTEXT (decl))) - return true; + bool refuse + = (DECL_CLASS_SCOPE_P (decl) + && CLASSTYPE_ERRONEOUS (DECL_CONTEXT (decl))); - for (; lev; lev = lev->next) - if (neglectable_inst_p (lev->maybe_get_node ())) - break; + if (!refuse) + { + for (; lev; lev = lev->next) + if (neglectable_inst_p (lev->maybe_get_node ())) + break; + refuse = (lev && errs > lev->errors); + } - return (lev && errs > lev->errors); + if (refuse) + { + /* Don't warn about it not being defined. */ + suppress_warning (decl, OPT_Wunused); + tree clone; + FOR_EACH_CLONE (clone, decl) + suppress_warning (clone, OPT_Wunused); + } + return refuse; } static int tinst_depth; -- cgit v1.1 From 47543e5f9d1fc502be79f91c87cbeb6eda17e641 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 3 Sep 2021 11:33:41 -0400 Subject: c++: shortcut bad convs during overload resolution [PR101904] In the context of overload resolution we have the notion of a "bad" argument conversion, which is a conversion that "would be a permitted with a bending of the language standards", and we handle such bad conversions specially. In particular, we rank a bad conversion as better than no conversion but worse than a good conversion, and a bad conversion doesn't necessarily make a candidate unviable. With the flag -fpermissive, we permit the situation where overload resolution selects a candidate that contains a bad conversion (which we call a non-strictly viable candidate). And without the flag, the caller of overload resolution usually issues a distinct permerror in this situation instead. One consequence of this defacto behavior is that in order to distinguish a non-strictly viable candidate from an unviable candidate, if we encounter a bad argument conversion during overload resolution we must keep converting subsequent arguments because a subsequent conversion could render the candidate unviable instead of just non-strictly viable. But checking subsequent arguments can force template instantiations and result in otherwise avoidable hard errors. And in particular, all 'this' conversions are at worst bad, so this means the const/ref-qualifiers of a member function can't be used to prune a candidate quickly, which is the subject of the mentioned PR. This patch tries to improve the situation without changing the defacto output of add_candidates. Specifically, when considering a candidate during overload resolution this patch makes us shortcut argument conversion checking upon encountering the first bad conversion (tentatively marking the candidate as non-strictly viable, though it could ultimately be unviable) under the assumption that we'll eventually find a strictly viable candidate anyway (which renders moot the distinction between non-strictly viable and unviable, since both are worse than a strictly viable candidate). If this assumption turns out to be false, we'll fully reconsider the candidate under the defacto behavior (without the shortcutting) so that all its conversions are computed. So in the best case (there's a strictly viable candidate), we avoid some argument conversions and/or template argument deduction that may cause a hard error. In the worst case (there's no such candidate), we have to redundantly consider some candidates twice. (In a previous version of the patch, to avoid this redundant checking I created a new "deferred" conversion type that represents a conversion that is yet to be computed, and instead of reconsidering a candidate I just realized its deferred conversions. But it doesn't seem this redundancy is a significant performance issue to justify the added complexity of this other approach.) PR c++/101904 gcc/cp/ChangeLog: * call.c (build_this_conversion): New function, split out from add_function_candidate. (add_function_candidate): New parameter shortcut_bad_convs. Document it. Use build_this_conversion. Stop at the first bad argument conversion when shortcut_bad_convs is true. (add_template_candidate_real): New parameter shortcut_bad_convs. Use build_this_conversion to check the 'this' conversion before attempting deduction. When the rejection reason code is rr_bad_arg_conversion, pass -1 instead of 0 as the viable parameter to add_candidate. Pass 'convs' to add_candidate. (add_template_candidate): New parameter shortcut_bad_convs. (add_template_conv_candidate): Pass false as shortcut_bad_convs to add_template_candidate_real. (add_candidates): Prefer to shortcut bad conversions during overload resolution under the assumption that we'll eventually see a strictly viable candidate. If this assumption turns out to be false, re-process the non-strictly viable candidates without shortcutting those bad conversions. gcc/testsuite/ChangeLog: * g++.dg/template/conv17.C: New test. --- gcc/cp/call.c | 250 +++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 177 insertions(+), 73 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 7bbf134..b6011c1 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -175,17 +175,17 @@ static struct z_candidate *splice_viable (struct z_candidate *, bool, bool *); static bool any_strictly_viable (struct z_candidate *); static struct z_candidate *add_template_candidate (struct z_candidate **, tree, tree, tree, tree, const vec *, - tree, tree, tree, int, unification_kind_t, tsubst_flags_t); + tree, tree, tree, int, unification_kind_t, bool, tsubst_flags_t); static struct z_candidate *add_template_candidate_real (struct z_candidate **, tree, tree, tree, tree, const vec *, - tree, tree, tree, int, tree, unification_kind_t, tsubst_flags_t); + tree, tree, tree, int, tree, unification_kind_t, bool, tsubst_flags_t); static bool is_complete (tree); static struct z_candidate *add_conv_candidate (struct z_candidate **, tree, tree, const vec *, tree, tree, tsubst_flags_t); static struct z_candidate *add_function_candidate (struct z_candidate **, tree, tree, tree, const vec *, tree, - tree, int, conversion**, tsubst_flags_t); + tree, int, conversion**, bool, tsubst_flags_t); static conversion *implicit_conversion (tree, tree, tree, bool, int, tsubst_flags_t); static conversion *reference_binding (tree, tree, tree, bool, int, @@ -2242,6 +2242,56 @@ conv_flags (int i, int nargs, tree fn, tree arg, int flags) return lflags; } +/* Build an appropriate 'this' conversion for the method FN and class + type CTYPE from the value ARG (having type ARGTYPE) to the type PARMTYPE. + This function modifies PARMTYPE, ARGTYPE and ARG. */ + +static conversion * +build_this_conversion (tree fn, tree ctype, + tree& parmtype, tree& argtype, tree& arg, + int flags, tsubst_flags_t complain) +{ + gcc_assert (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + && !DECL_CONSTRUCTOR_P (fn)); + + /* The type of the implicit object parameter ('this') for + overload resolution is not always the same as for the + function itself; conversion functions are considered to + be members of the class being converted, and functions + introduced by a using-declaration are considered to be + members of the class that uses them. + + Since build_over_call ignores the ICS for the `this' + parameter, we can just change the parm type. */ + parmtype = cp_build_qualified_type (ctype, + cp_type_quals (TREE_TYPE (parmtype))); + bool this_p = true; + if (FUNCTION_REF_QUALIFIED (TREE_TYPE (fn))) + { + /* If the function has a ref-qualifier, the implicit + object parameter has reference type. */ + bool rv = FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (fn)); + parmtype = cp_build_reference_type (parmtype, rv); + /* The special handling of 'this' conversions in compare_ics + does not apply if there is a ref-qualifier. */ + this_p = false; + } + else + { + parmtype = build_pointer_type (parmtype); + /* We don't use build_this here because we don't want to + capture the object argument until we've chosen a + non-static member function. */ + arg = build_address (arg); + argtype = lvalue_type (arg); + } + flags |= LOOKUP_ONLYCONVERTING; + conversion *t = implicit_conversion (parmtype, argtype, arg, + /*c_cast_p=*/false, flags, complain); + t->this_p = this_p; + return t; +} + /* Create an overload candidate for the function or method FN called with the argument list FIRST_ARG/ARGS and add it to CANDIDATES. FLAGS is passed on to implicit_conversion. @@ -2249,7 +2299,14 @@ conv_flags (int i, int nargs, tree fn, tree arg, int flags) This does not change ARGS. CTYPE, if non-NULL, is the type we want to pretend this function - comes from for purposes of overload resolution. */ + comes from for purposes of overload resolution. + + SHORTCUT_BAD_CONVS controls how we handle "bad" argument conversions. + If true, we stop computing conversions upon seeing the first bad + conversion. This is used by add_candidates to avoid computing + more conversions than necessary in the presence of a strictly viable + candidate, while preserving the defacto behavior of overload resolution + when it turns out there are only non-strictly viable candidates. */ static struct z_candidate * add_function_candidate (struct z_candidate **candidates, @@ -2257,6 +2314,7 @@ add_function_candidate (struct z_candidate **candidates, const vec *args, tree access_path, tree conversion_path, int flags, conversion **convs, + bool shortcut_bad_convs, tsubst_flags_t complain) { tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (fn)); @@ -2378,8 +2436,6 @@ add_function_candidate (struct z_candidate **candidates, { tree argtype, to_type; tree arg; - conversion *t; - int is_this; if (parmnode == void_list_node) break; @@ -2398,54 +2454,23 @@ add_function_candidate (struct z_candidate **candidates, (*args)[i + skip - (first_arg != NULL_TREE ? 1 : 0)]); argtype = lvalue_type (arg); - is_this = (i == 0 && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) - && ! DECL_CONSTRUCTOR_P (fn)); - + conversion *t; if (parmnode) { tree parmtype = TREE_VALUE (parmnode); - - parmnode = TREE_CHAIN (parmnode); - - /* The type of the implicit object parameter ('this') for - overload resolution is not always the same as for the - function itself; conversion functions are considered to - be members of the class being converted, and functions - introduced by a using-declaration are considered to be - members of the class that uses them. - - Since build_over_call ignores the ICS for the `this' - parameter, we can just change the parm type. */ - if (ctype && is_this) + if (i == 0 + && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + && !DECL_CONSTRUCTOR_P (fn)) + t = build_this_conversion (fn, ctype, parmtype, argtype, arg, + flags, complain); + else { - parmtype = cp_build_qualified_type - (ctype, cp_type_quals (TREE_TYPE (parmtype))); - if (FUNCTION_REF_QUALIFIED (TREE_TYPE (fn))) - { - /* If the function has a ref-qualifier, the implicit - object parameter has reference type. */ - bool rv = FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (fn)); - parmtype = cp_build_reference_type (parmtype, rv); - /* The special handling of 'this' conversions in compare_ics - does not apply if there is a ref-qualifier. */ - is_this = false; - } - else - { - parmtype = build_pointer_type (parmtype); - /* We don't use build_this here because we don't want to - capture the object argument until we've chosen a - non-static member function. */ - arg = build_address (arg); - argtype = lvalue_type (arg); - } + int lflags = conv_flags (i, len-skip, fn, arg, flags); + t = implicit_conversion (parmtype, argtype, arg, + /*c_cast_p=*/false, lflags, complain); } - - int lflags = conv_flags (i, len-skip, fn, arg, flags); - - t = implicit_conversion (parmtype, argtype, arg, - /*c_cast_p=*/false, lflags, complain); to_type = parmtype; + parmnode = TREE_CHAIN (parmnode); } else { @@ -2454,9 +2479,6 @@ add_function_candidate (struct z_candidate **candidates, to_type = argtype; } - if (t && is_this) - t->this_p = true; - convs[i] = t; if (! t) { @@ -2471,7 +2493,8 @@ add_function_candidate (struct z_candidate **candidates, viable = -1; reason = bad_arg_conversion_rejection (first_arg, i, arg, to_type, EXPR_LOCATION (arg)); - + if (shortcut_bad_convs) + break; } } @@ -3355,7 +3378,9 @@ add_builtin_candidates (struct z_candidate **candidates, enum tree_code code, This does not change ARGLIST. The RETURN_TYPE is the desired type for conversion operators. If OBJ is NULL_TREE, FLAGS and CTYPE are as for add_function_candidate. If an OBJ is supplied, FLAGS and - CTYPE are ignored, and OBJ is as for add_conv_candidate. */ + CTYPE are ignored, and OBJ is as for add_conv_candidate. + + SHORTCUT_BAD_CONVS is as in add_function_candidate. */ static struct z_candidate* add_template_candidate_real (struct z_candidate **candidates, tree tmpl, @@ -3363,7 +3388,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, const vec *arglist, tree return_type, tree access_path, tree conversion_path, int flags, tree obj, unification_kind_t strict, - tsubst_flags_t complain) + bool shortcut_bad_convs, tsubst_flags_t complain) { int ntparms = DECL_NTPARMS (tmpl); tree targs = make_tree_vec (ntparms); @@ -3493,7 +3518,33 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, errs = errorcount+sorrycount; if (!obj) - convs = alloc_conversions (nargs); + { + convs = alloc_conversions (nargs); + + if (shortcut_bad_convs + && DECL_NONSTATIC_MEMBER_FUNCTION_P (tmpl) + && !DECL_CONSTRUCTOR_P (tmpl)) + { + /* Check the 'this' conversion before proceeding with deduction. + This is effectively an extension of the DR 1391 resolution + that we perform in check_non_deducible_conversions, though it's + convenient to do this extra check here instead of there. */ + tree parmtype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (tmpl))); + tree argtype = lvalue_type (first_arg); + tree arg = first_arg; + conversion *t = build_this_conversion (tmpl, ctype, + parmtype, argtype, arg, + flags, complain); + convs[0] = t; + if (t->bad_p) + { + reason = bad_arg_conversion_rejection (first_arg, 0, + arg, parmtype, + EXPR_LOCATION (arg)); + goto fail; + } + } + } fn = fn_type_unification (tmpl, explicit_targs, targs, args_without_in_chrg, nargs_without_in_chrg, @@ -3540,7 +3591,8 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, else cand = add_function_candidate (candidates, fn, ctype, first_arg, arglist, access_path, - conversion_path, flags, convs, complain); + conversion_path, flags, convs, + shortcut_bad_convs, complain); if (DECL_TI_TEMPLATE (fn) != tmpl) /* This situation can occur if a member template of a template class is specialized. Then, instantiate_template might return @@ -3566,8 +3618,9 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, return cand; fail: - return add_candidate (candidates, tmpl, first_arg, arglist, nargs, NULL, - access_path, conversion_path, 0, reason, flags); + int viable = (reason->code == rr_bad_arg_conversion ? -1 : 0); + return add_candidate (candidates, tmpl, first_arg, arglist, nargs, convs, + access_path, conversion_path, viable, reason, flags); } @@ -3576,13 +3629,15 @@ add_template_candidate (struct z_candidate **candidates, tree tmpl, tree ctype, tree explicit_targs, tree first_arg, const vec *arglist, tree return_type, tree access_path, tree conversion_path, int flags, - unification_kind_t strict, tsubst_flags_t complain) + unification_kind_t strict, bool shortcut_bad_convs, + tsubst_flags_t complain) { return add_template_candidate_real (candidates, tmpl, ctype, explicit_targs, first_arg, arglist, return_type, access_path, conversion_path, - flags, NULL_TREE, strict, complain); + flags, NULL_TREE, strict, shortcut_bad_convs, + complain); } /* Create an overload candidate for the conversion function template TMPL, @@ -3608,7 +3663,7 @@ add_template_conv_candidate (struct z_candidate **candidates, tree tmpl, add_template_candidate_real (candidates, tmpl, NULL_TREE, NULL_TREE, NULL_TREE, arglist, return_type, access_path, conversion_path, 0, obj, DEDUCE_CALL, - complain); + /*shortcut_bad_convs=*/false, complain); } /* The CANDS are the set of candidates that were considered for @@ -6060,6 +6115,7 @@ add_candidates (tree fns, tree first_arg, const vec *args, /* Delay creating the implicit this parameter until it is needed. */ non_static_args = NULL; + bool seen_strictly_viable = any_strictly_viable (*candidates); /* If there's a non-template perfect match, we don't need to consider templates. So check non-templates first. This optimization is only really needed for the defaulted copy constructor of tuple and the like @@ -6071,6 +6127,19 @@ add_candidates (tree fns, tree first_arg, const vec *args, else /*if (flags & LOOKUP_DEFAULTED)*/ which = non_templates; + /* During overload resolution, we first consider each function under the + assumption that we'll eventually find a strictly viable candidate. + This allows us to circumvent our defacto behavior when checking + argument conversions and shortcut consideration of the candidate + upon encountering the first bad conversion. If this assumption + turns out to be false, and all candidates end up being non-strictly + viable, then we reconsider such candidates under the defacto behavior. + This trick is important for pruning member function overloads according + to their const/ref-qualifiers (since all 'this' conversions are at + worst bad) without breaking -fpermissive. */ + tree bad_fns = NULL_TREE; + bool shortcut_bad_convs = true; + again: for (tree fn : lkp_range (fns)) { @@ -6117,18 +6186,22 @@ add_candidates (tree fns, tree first_arg, const vec *args, } if (TREE_CODE (fn) == TEMPLATE_DECL) - add_template_candidate (candidates, - fn, - ctype, - explicit_targs, - fn_first_arg, - fn_args, - return_type, - access_path, - conversion_path, - flags, - strict, - complain); + { + if (!add_template_candidate (candidates, + fn, + ctype, + explicit_targs, + fn_first_arg, + fn_args, + return_type, + access_path, + conversion_path, + flags, + strict, + shortcut_bad_convs, + complain)) + continue; + } else { add_function_candidate (candidates, @@ -6140,16 +6213,47 @@ add_candidates (tree fns, tree first_arg, const vec *args, conversion_path, flags, NULL, + shortcut_bad_convs, complain); if (perfect_candidate_p (*candidates)) seen_perfect = true; } + + z_candidate *cand = *candidates; + if (cand->viable == 1) + seen_strictly_viable = true; + + if (cand->viable == -1 + && shortcut_bad_convs + && !cand->convs[cand->reversed () ? 0 : cand->num_convs - 1]) + { + /* This candidate has been tentatively marked non-strictly viable, + and we didn't compute all argument conversions for it (having + stopped at the first bad conversion). Add the function to BAD_FNS + to fully reconsider later if we don't find any strictly viable + candidates. */ + bad_fns = lookup_add (fn, bad_fns); + *candidates = (*candidates)->next; + } } if (which == non_templates && !seen_perfect) { which = templates; goto again; } + else if (which == templates + && !seen_strictly_viable + && shortcut_bad_convs + && bad_fns) + { + /* None of the candidates are strictly viable, so consider again those + functions in BAD_FNS, this time without shortcutting bad conversions + so that all their argument conversions are computed. */ + which = either; + fns = bad_fns; + shortcut_bad_convs = false; + goto again; + } } /* Returns 1 if P0145R2 says that the LHS of operator CODE is evaluated first, -- cgit v1.1 From 88974974d8188cf12e87e4ad3d23a8cbdd557f0e Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Wed, 23 Jun 2021 08:19:13 +0100 Subject: coroutines: Use DECL_VALUE_EXPR instead of rewriting vars. Variables that need to persist over suspension expressions must be preserved by being copied into the coroutine frame. The initial implementations do this manually in the transform code. However, that has various disadvantages - including that the debug connections are lost between the original var and the frame copy. The revised implementation makes use of DECL_VALUE_EXPRs to contain the frame offset expressions, so that the original var names are preserved in the code. This process is also applied to the function parms which are always copied to the frame. In this case the decls need to be copied since they are used in two different contexts during the re-write (in the building of the ramp function, and in the actor function itself). This will assist in improvement of debugging (PR 99215). Signed-off-by: Iain Sandoe gcc/cp/ChangeLog: * coroutines.cc (transform_local_var_uses): Record frame offset expressions as DECL_VALUE_EXPRs instead of rewriting them. --- gcc/cp/coroutines.cc | 105 +++------------------------------------------------ 1 file changed, 5 insertions(+), 100 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index ceb3d3b..2d68098f 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1974,8 +1974,7 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d) local_vars_transform *lvd = (local_vars_transform *) d; /* For each var in this bind expr (that has a frame id, which means it was - accessed), build a frame reference for each and then walk the bind expr - statements, substituting the frame ref for the original var. */ + accessed), build a frame reference and add it as the DECL_VALUE_EXPR. */ if (TREE_CODE (*stmt) == BIND_EXPR) { @@ -1991,13 +1990,9 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d) /* Re-write the variable's context to be in the actor func. */ DECL_CONTEXT (lvar) = lvd->context; - /* For capture proxies, this could include the decl value expr. */ - if (local_var.is_lambda_capture || local_var.has_value_expr_p) - { - tree ve = DECL_VALUE_EXPR (lvar); - cp_walk_tree (&ve, transform_local_var_uses, d, NULL); + /* For capture proxies, this could include the decl value expr. */ + if (local_var.is_lambda_capture || local_var.has_value_expr_p) continue; /* No frame entry for this. */ - } /* TODO: implement selective generation of fields when vars are known not-used. */ @@ -2011,103 +2006,13 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d) tree fld_idx = build3_loc (lvd->loc, COMPONENT_REF, TREE_TYPE (lvar), lvd->actor_frame, fld_ref, NULL_TREE); local_var.field_idx = fld_idx; - } - /* FIXME: we should be able to do this in the loop above, but (at least - for range for) there are cases where the DECL_INITIAL contains - forward references. - So, now we've built the revised var in the frame, substitute uses of - it in initializers and the bind expr body. */ - for (lvar = BIND_EXPR_VARS (*stmt); lvar != NULL; - lvar = DECL_CHAIN (lvar)) - { - /* we need to walk some of the decl trees, which might contain - references to vars replaced at a higher level. */ - cp_walk_tree (&DECL_INITIAL (lvar), transform_local_var_uses, d, - NULL); - cp_walk_tree (&DECL_SIZE (lvar), transform_local_var_uses, d, NULL); - cp_walk_tree (&DECL_SIZE_UNIT (lvar), transform_local_var_uses, d, - NULL); + SET_DECL_VALUE_EXPR (lvar, fld_idx); + DECL_HAS_VALUE_EXPR_P (lvar) = true; } cp_walk_tree (&BIND_EXPR_BODY (*stmt), transform_local_var_uses, d, NULL); - - /* Now we have processed and removed references to the original vars, - we can drop those from the bind - leaving capture proxies alone. */ - for (tree *pvar = &BIND_EXPR_VARS (*stmt); *pvar != NULL;) - { - bool existed; - local_var_info &local_var - = lvd->local_var_uses->get_or_insert (*pvar, &existed); - gcc_checking_assert (existed); - - /* Leave lambda closure captures alone, we replace the *this - pointer with the frame version and let the normal process - deal with the rest. - Likewise, variables with their value found elsewhere. - Skip past unused ones too. */ - if (local_var.is_lambda_capture - || local_var.has_value_expr_p - || local_var.field_id == NULL_TREE) - { - pvar = &DECL_CHAIN (*pvar); - continue; - } - - /* Discard this one, we replaced it. */ - *pvar = DECL_CHAIN (*pvar); - } - *do_subtree = 0; /* We've done the body already. */ return NULL_TREE; } - - tree var_decl = *stmt; - /* Look inside cleanups, we don't want to wrap a statement list in a - cleanup. */ - bool needs_cleanup = true; - if (TREE_CODE (var_decl) == CLEANUP_POINT_EXPR) - var_decl = TREE_OPERAND (var_decl, 0); - else - needs_cleanup = false; - - /* Look inside the decl_expr for the actual var. */ - bool decl_expr_p = TREE_CODE (var_decl) == DECL_EXPR; - if (decl_expr_p && TREE_CODE (DECL_EXPR_DECL (var_decl)) == VAR_DECL) - var_decl = DECL_EXPR_DECL (var_decl); - else if (TREE_CODE (var_decl) != VAR_DECL) - return NULL_TREE; - - /* VAR_DECLs that are not recorded can belong to the proxies we've placed - for the promise and coroutine handle(s), to global vars or to compiler - temporaries. Skip past these, we will handle them later. */ - local_var_info *local_var_i = lvd->local_var_uses->get (var_decl); - - if (local_var_i == NULL) - return NULL_TREE; - - if (local_var_i->is_lambda_capture - || local_var_i->is_static - || local_var_i->has_value_expr_p) - return NULL_TREE; - - /* This is our revised 'local' i.e. a frame slot. */ - tree revised = local_var_i->field_idx; - gcc_checking_assert (DECL_CONTEXT (var_decl) == lvd->context); - - if (decl_expr_p && DECL_INITIAL (var_decl)) - { - location_t loc = DECL_SOURCE_LOCATION (var_decl); - tree r - = cp_build_modify_expr (loc, revised, INIT_EXPR, - DECL_INITIAL (var_decl), tf_warning_or_error); - if (needs_cleanup) - r = coro_build_cvt_void_expr_stmt (r, EXPR_LOCATION (*stmt)); - *stmt = r; - } - else - *stmt = revised; - - if (decl_expr_p) - *do_subtree = 0; /* We've accounted for the nested use. */ return NULL_TREE; } -- cgit v1.1 From a45a7ecdf34311587daa2e90cc732adcefac447b Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Wed, 7 Jul 2021 19:53:45 +0100 Subject: coroutines: Add a helper for creating local vars. This is primarily code factoring, but we take this opportunity to rename some of the implementation variables (which we intend to expose to debugging) so that they are in the implementation namespace. Signed-off-by: Iain Sandoe gcc/cp/ChangeLog: * coroutines.cc (coro_build_artificial_var): New. (build_actor_fn): Use var builder, rename vars to use implementation namespace. (coro_rewrite_function_body): Likewise. (morph_fn_to_coro): Likewise. --- gcc/cp/coroutines.cc | 71 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 26 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 2d68098f..a3c780e 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1474,6 +1474,29 @@ coro_build_cvt_void_expr_stmt (tree expr, location_t loc) return coro_build_expr_stmt (t, loc); } +/* Helpers to build an artificial var, with location LOC, NAME and TYPE, in + CTX, and with initializer INIT. */ + +static tree +coro_build_artificial_var (location_t loc, tree name, tree type, tree ctx, + tree init) +{ + tree res = build_lang_decl (VAR_DECL, name, type); + DECL_SOURCE_LOCATION (res) = loc; + DECL_CONTEXT (res) = ctx; + DECL_ARTIFICIAL (res) = true; + DECL_INITIAL (res) = init; + return res; +} + +static tree +coro_build_artificial_var (location_t loc, const char *name, tree type, + tree ctx, tree init) +{ + return coro_build_artificial_var (loc, get_identifier (name), + type, ctx, init); +} + /* Helpers for label creation: 1. Create a named label in the specified context. */ @@ -2113,12 +2136,10 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, tree top_block = make_node (BLOCK); BIND_EXPR_BLOCK (actor_bind) = top_block; - tree continuation = build_lang_decl (VAR_DECL, - get_identifier ("actor.continue"), - void_coro_handle_type); - DECL_ARTIFICIAL (continuation) = 1; - DECL_IGNORED_P (continuation) = 1; - DECL_CONTEXT (continuation) = actor; + tree continuation = coro_build_artificial_var (loc, "_Coro_actor_continue", + void_coro_handle_type, actor, + NULL_TREE); + BIND_EXPR_VARS (actor_bind) = continuation; /* Link in the block associated with the outer scope of the re-written @@ -4069,12 +4090,13 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, fn_start, NULL, /*musthave=*/true); /* Create and initialize the initial-await-resume-called variable per [dcl.fct.def.coroutine] / 5.3. */ - tree i_a_r_c = build_lang_decl (VAR_DECL, get_identifier ("i_a_r_c"), - boolean_type_node); - DECL_ARTIFICIAL (i_a_r_c) = true; + tree i_a_r_c + = coro_build_artificial_var (fn_start, + "_Coro_initial_await_resume_called", + boolean_type_node, orig, + boolean_false_node); DECL_CHAIN (i_a_r_c) = var_list; var_list = i_a_r_c; - DECL_INITIAL (i_a_r_c) = boolean_false_node; add_decl_expr (i_a_r_c); /* Start the try-catch. */ tree tcb = build_stmt (fn_start, TRY_BLOCK, NULL_TREE, NULL_TREE); @@ -4459,8 +4481,10 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) add_stmt (ramp_bind); tree ramp_body = push_stmt_list (); - tree coro_fp = build_lang_decl (VAR_DECL, get_identifier ("coro.frameptr"), - coro_frame_ptr); + tree zeroinit = build1_loc (fn_start, CONVERT_EXPR, + coro_frame_ptr, integer_zero_node); + tree coro_fp = coro_build_artificial_var (fn_start, "_Coro_frameptr", + coro_frame_ptr, orig, zeroinit); tree varlist = coro_fp; /* To signal that we need to cleanup copied function args. */ @@ -4478,21 +4502,19 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* Signal that we need to clean up the promise object on exception. */ tree coro_promise_live - = build_lang_decl (VAR_DECL, get_identifier ("coro.promise.live"), - boolean_type_node); - DECL_ARTIFICIAL (coro_promise_live) = true; + = coro_build_artificial_var (fn_start, "_Coro_promise_live", + boolean_type_node, orig, boolean_false_node); DECL_CHAIN (coro_promise_live) = varlist; varlist = coro_promise_live; - DECL_INITIAL (coro_promise_live) = boolean_false_node; + /* When the get-return-object is in the RETURN slot, we need to arrange for cleanup on exception. */ tree coro_gro_live - = build_lang_decl (VAR_DECL, get_identifier ("coro.gro.live"), - boolean_type_node); - DECL_ARTIFICIAL (coro_gro_live) = true; + = coro_build_artificial_var (fn_start, "_Coro_gro_live", + boolean_type_node, orig, boolean_false_node); + DECL_CHAIN (coro_gro_live) = varlist; varlist = coro_gro_live; - DECL_INITIAL (coro_gro_live) = boolean_false_node; /* Collected the scope vars we need ... only one for now. */ BIND_EXPR_VARS (ramp_bind) = nreverse (varlist); @@ -4508,8 +4530,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* The decl_expr for the coro frame pointer, initialize to zero so that we can pass it to the IFN_CO_FRAME (since there's no way to pass a type, directly apparently). This avoids a "used uninitialized" warning. */ - tree zeroinit = build1 (CONVERT_EXPR, coro_frame_ptr, integer_zero_node); - DECL_INITIAL (coro_fp) = zeroinit; + add_decl_expr (coro_fp); if (flag_exceptions && DECL_ARGUMENTS (orig)) for (tree arg = DECL_ARGUMENTS (orig); arg != NULL; @@ -4969,10 +4990,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) { /* ... or ... Construct an object that will be used as the single param to the CTOR for the return object. */ - gro = build_lang_decl (VAR_DECL, get_identifier ("coro.gro"), gro_type); - DECL_CONTEXT (gro) = current_scope (); - DECL_ARTIFICIAL (gro) = true; - DECL_IGNORED_P (gro) = true; + gro = coro_build_artificial_var (fn_start, "_Coro_gro", gro_type, orig, + NULL_TREE); add_decl_expr (gro); gro_bind_vars = gro; r = cp_build_modify_expr (input_location, gro, INIT_EXPR, get_ro, -- cgit v1.1 From addf167a23f61c0ec97f6e71577a0623f3fc13e7 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Fri, 9 Jul 2021 21:01:41 +0100 Subject: coroutines: Support for debugging implementation state. Some of the state that is associated with the implementation is of interest to a user debugging a coroutine. In particular items such as the suspend point, promise object, and current suspend point. These variables live in the coroutine frame, but we can inject proxies for them into the outermost bind expression of the coroutine. Such variables are automatically moved into the coroutine frame (if they need to persist across a suspend expression). PLacing the proxies thus allows the user to inspect them by name in the debugger. To implement this, we ensure that (at the outermost scope) the frame entries are not mangled (coroutine frame variables are usually mangled with scope nesting information so that they do not clash). We can safely avoid doing this for the outermost scope so that we can map frame entries directly to the variables. This is partial contribution to debug support (PR 99215). Signed-off-by: Iain Sandoe gcc/cp/ChangeLog: * coroutines.cc (register_local_var_uses): Do not mangle frame entries for the outermost scope. Record the outer scope as nesting depth 0. --- gcc/cp/coroutines.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index a3c780e..9ab2be0 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -3885,8 +3885,6 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) if (TREE_CODE (*stmt) == BIND_EXPR) { - lvd->bind_indx++; - lvd->nest_depth++; tree lvar; for (lvar = BIND_EXPR_VARS (*stmt); lvar != NULL; lvar = DECL_CHAIN (lvar)) @@ -3925,11 +3923,17 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) continue; /* Make names depth+index unique, so that we can support nested - scopes with identically named locals. */ + scopes with identically named locals and still be able to + identify them in the coroutine frame. */ tree lvname = DECL_NAME (lvar); char *buf; - if (lvname != NULL_TREE) - buf = xasprintf ("__%s.%u.%u", IDENTIFIER_POINTER (lvname), + /* The outermost bind scope contains the artificial variables that + we inject to implement the coro state machine. We want to be able + to inspect these in debugging. */ + if (lvname != NULL_TREE && lvd->nest_depth == 0) + buf = xasprintf ("%s", IDENTIFIER_POINTER (lvname)); + else if (lvname != NULL_TREE) + buf = xasprintf ("%s_%u_%u", IDENTIFIER_POINTER (lvname), lvd->nest_depth, lvd->bind_indx); else buf = xasprintf ("_D%u.%u.%u", DECL_UID (lvar), lvd->nest_depth, @@ -3942,6 +3946,8 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) /* We don't walk any of the local var sub-trees, they won't contain any bind exprs. */ } + lvd->bind_indx++; + lvd->nest_depth++; cp_walk_tree (&BIND_EXPR_BODY (*stmt), register_local_var_uses, d, NULL); *do_subtree = 0; /* We've done this. */ lvd->nest_depth--; -- cgit v1.1 From 7b7395409c7aaef493337479c7fd586e52aea3d1 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 4 Sep 2021 00:16:38 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d969b31..6d8a6d3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,59 @@ +2021-09-03 Iain Sandoe + + * coroutines.cc (register_local_var_uses): Do not mangle + frame entries for the outermost scope. Record the outer + scope as nesting depth 0. + +2021-09-03 Iain Sandoe + + * coroutines.cc (coro_build_artificial_var): New. + (build_actor_fn): Use var builder, rename vars to use + implementation namespace. + (coro_rewrite_function_body): Likewise. + (morph_fn_to_coro): Likewise. + +2021-09-03 Iain Sandoe + + * coroutines.cc (transform_local_var_uses): Record + frame offset expressions as DECL_VALUE_EXPRs instead of + rewriting them. + +2021-09-03 Patrick Palka + + PR c++/101904 + * call.c (build_this_conversion): New function, split out from + add_function_candidate. + (add_function_candidate): New parameter shortcut_bad_convs. + Document it. Use build_this_conversion. Stop at the first bad + argument conversion when shortcut_bad_convs is true. + (add_template_candidate_real): New parameter shortcut_bad_convs. + Use build_this_conversion to check the 'this' conversion before + attempting deduction. When the rejection reason code is + rr_bad_arg_conversion, pass -1 instead of 0 as the viable + parameter to add_candidate. Pass 'convs' to add_candidate. + (add_template_candidate): New parameter shortcut_bad_convs. + (add_template_conv_candidate): Pass false as shortcut_bad_convs + to add_template_candidate_real. + (add_candidates): Prefer to shortcut bad conversions during + overload resolution under the assumption that we'll eventually + see a strictly viable candidate. If this assumption turns out + to be false, re-process the non-strictly viable candidates + without shortcutting those bad conversions. + +2021-09-03 Jason Merrill + + * pt.c (limit_bad_template_recursion): Suppress -Wunused for decls + we decide not to instantiate. + +2021-09-03 Jakub Jelinek + + PR target/102024 + * class.c (build_base_field): Use SET_DECL_FIELD_ABI_IGNORED + instead of writing to DECL_FIELD_ABI_IGNORED. + (layout_class_type): Likewise. In the place where zero-width + bitfields used to be removed, use + SET_DECL_FIELD_CXX_ZERO_WIDTH_BIT_FIELD on those fields instead. + 2021-09-01 Iain Sandoe * call.c (build_over_call): Handle unavailable state in addition to -- 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/parser.c | 7 +++++-- gcc/cp/semantics.c | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ea71f9c..f9c2c8a 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -40742,7 +40742,9 @@ cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); - if (!strcmp (p, "acq_rel")) + if (!strcmp (p, "seq_cst")) + mo = MEMMODEL_SEQ_CST; + else if (!strcmp (p, "acq_rel")) mo = MEMMODEL_ACQ_REL; else if (!strcmp (p, "release")) mo = MEMMODEL_RELEASE; @@ -40750,7 +40752,8 @@ cp_parser_omp_flush (cp_parser *parser, cp_token *pragma_tok) mo = MEMMODEL_ACQUIRE; else error_at (cp_lexer_peek_token (parser->lexer)->location, - "expected %, % or %"); + "expected %, %, % or " + "%"); cp_lexer_consume_token (parser->lexer); } if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) 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 81f9718139cb1cc164ada411ada8cca9f32b8be8 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 7 Sep 2021 19:33:28 +0200 Subject: c++: Fix up constexpr evaluation of deleting dtors [PR100495] We do not save bodies of constexpr clones and instead evaluate the bodies of the constexpr functions they were cloned from. I believe that is just fine for constructors because complete vs. base ctors differ only in classes that have virtual bases and such constructors aren't constexpr, similarly complete/base destructors. But as the testcase below shows, for deleting destructors it is not fine, deleting dtors while marked as clones in fact are just artificial functions with synthetized body which calls the user destructor and deallocation. So, either we'd need to evaluate the destructor and afterwards synthetize and evaluate the deallocation, or we can just save and use the deleting dtors bodies. The latter seems much easier to me. 2021-09-07 Jakub Jelinek PR c++/100495 * constexpr.c (maybe_save_constexpr_fundef): Save body even for constexpr deleting dtors. (cxx_eval_call_expression): Don't use DECL_CLONED_FUNCTION for deleting dtors. * g++.dg/cpp2a/constexpr-new21.C: New test. --- gcc/cp/constexpr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 45adbab..7772fe6 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -865,7 +865,7 @@ maybe_save_constexpr_fundef (tree fun) if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun) || cp_function_chain->invalid_constexpr - || DECL_CLONED_FUNCTION_P (fun)) + || (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun))) return; if (!is_valid_constexpr_fn (fun, !DECL_GENERATED_P (fun))) @@ -2372,7 +2372,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, *non_constant_p = true; return t; } - if (DECL_CLONED_FUNCTION_P (fun)) + if (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun)) fun = DECL_CLONED_FUNCTION (fun); if (is_ubsan_builtin_p (fun)) -- cgit v1.1 From b2748138c05c6fba1a34f54980b6382bc6332f56 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 8 Sep 2021 00:16:23 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6d8a6d3..2b4bbdc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2021-09-07 Jakub Jelinek + + PR c++/100495 + * constexpr.c (maybe_save_constexpr_fundef): Save body even for + constexpr deleting dtors. + (cxx_eval_call_expression): Don't use DECL_CLONED_FUNCTION for + deleting dtors. + +2021-09-07 Marcel Vollweiler + + * parser.c (cp_parser_omp_flush): Parse 'seq_cst' clause on 'flush' + directive. + * semantics.c (finish_omp_flush): Handle MEMMODEL_SEQ_CST. + 2021-09-03 Iain Sandoe * coroutines.cc (register_local_var_uses): Do not mangle -- 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/cp-tree.h | 4 ++++ gcc/cp/decl.c | 3 +++ gcc/cp/decl2.c | 17 +++++++++-------- gcc/cp/module.cc | 10 ++++++++-- gcc/cp/semantics.c | 8 ++++++++ gcc/cp/typeck.c | 32 +++++--------------------------- 6 files changed, 37 insertions(+), 37 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 435f32b..ceb5359 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4800,6 +4800,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define ANON_UNION_TYPE_P(NODE) \ (TREE_CODE (NODE) == UNION_TYPE && ANON_AGGR_TYPE_P (NODE)) +/* For an ANON_AGGR_TYPE_P the single FIELD_DECL it is used with. */ +#define ANON_AGGR_TYPE_FIELD(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->typeinfo_var) + /* Define fields and accessors for nodes representing declared names. */ /* True if TYPE is an unnamed structured type with a typedef for diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 146979b..bce62ad 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5096,6 +5096,9 @@ fixup_anonymous_aggr (tree t) (*vec)[store++] = elt; vec_safe_truncate (vec, store); + /* Wipe RTTI info. */ + CLASSTYPE_TYPEINFO_VAR (t) = NULL_TREE; + /* Anonymous aggregates cannot have fields with ctors, dtors or complex assignment operators (because they cannot have these methods themselves). For anonymous unions this is already checked because they are not allowed diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 107edca..a79a70b 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -2977,14 +2977,15 @@ reset_type_linkage (tree type) SET_DECL_ASSEMBLER_NAME (vt, name); reset_decl_linkage (vt); } - if (tree ti = CLASSTYPE_TYPEINFO_VAR (type)) - { - tree name = mangle_typeinfo_for_type (type); - DECL_NAME (ti) = name; - SET_DECL_ASSEMBLER_NAME (ti, name); - TREE_TYPE (name) = type; - reset_decl_linkage (ti); - } + if (!ANON_AGGR_TYPE_P (type)) + if (tree ti = CLASSTYPE_TYPEINFO_VAR (type)) + { + tree name = mangle_typeinfo_for_type (type); + DECL_NAME (ti) = name; + SET_DECL_ASSEMBLER_NAME (ti, name); + TREE_TYPE (name) = type; + reset_decl_linkage (ti); + } for (tree m = TYPE_FIELDS (type); m; m = DECL_CHAIN (m)) { tree mem = STRIP_TEMPLATE (m); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 4b2ad6f..71d0fab 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -11859,8 +11859,9 @@ trees_in::read_class_def (tree defn, tree maybe_template) { CLASSTYPE_BEFRIENDING_CLASSES (type_dup) = CLASSTYPE_BEFRIENDING_CLASSES (type); - CLASSTYPE_TYPEINFO_VAR (type_dup) - = CLASSTYPE_TYPEINFO_VAR (type); + if (!ANON_AGGR_TYPE_P (type)) + CLASSTYPE_TYPEINFO_VAR (type_dup) + = CLASSTYPE_TYPEINFO_VAR (type); } for (tree v = type; v; v = TYPE_NEXT_VARIANT (v)) TYPE_LANG_SPECIFIC (v) = ls; @@ -11891,6 +11892,11 @@ trees_in::read_class_def (tree defn, tree maybe_template) *chain = decl; chain = &DECL_CHAIN (decl); + if (TREE_CODE (decl) == FIELD_DECL + && ANON_AGGR_TYPE_P (TREE_TYPE (decl))) + ANON_AGGR_TYPE_FIELD + (TYPE_MAIN_VARIANT (TREE_TYPE (decl))) = decl; + if (TREE_CODE (decl) == USING_DECL && TREE_CODE (USING_DECL_SCOPE (decl)) == RECORD_TYPE) { 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. */ diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index cc61b50..a2398db 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2618,36 +2618,14 @@ rationalize_conditional_expr (enum tree_code code, tree t, that are directly reachable. */ tree -lookup_anon_field (tree t, tree type) +lookup_anon_field (tree, tree type) { tree field; - t = TYPE_MAIN_VARIANT (t); - - for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) - { - if (TREE_STATIC (field)) - continue; - if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field)) - continue; - - /* If we find it directly, return the field. */ - if (DECL_NAME (field) == NULL_TREE - && type == TYPE_MAIN_VARIANT (TREE_TYPE (field))) - { - return field; - } - - /* Otherwise, it could be nested, search harder. */ - if (DECL_NAME (field) == NULL_TREE - && ANON_AGGR_TYPE_P (TREE_TYPE (field))) - { - tree subfield = lookup_anon_field (TREE_TYPE (field), type); - if (subfield) - return subfield; - } - } - return NULL_TREE; + type = TYPE_MAIN_VARIANT (type); + field = ANON_AGGR_TYPE_FIELD (type); + gcc_assert (field); + return field; } /* Build an expression representing OBJECT.MEMBER. OBJECT is an -- cgit v1.1 From b6db7cd41ccf821ffb10ff4f18845465e98803cd Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 9 Sep 2021 00:16:32 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2b4bbdc..84b9b97 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,18 @@ +2021-09-08 Richard Biener + + PR c++/102228 + * 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. + 2021-09-07 Jakub Jelinek PR c++/100495 -- 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/parser.c | 24 ++++++++---------------- gcc/cp/semantics.c | 2 +- 2 files changed, 9 insertions(+), 17 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index f9c2c8a..e44c5c6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -40193,7 +40193,6 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) memory_order = OMP_MEMORY_ORDER_ACQUIRE; break; case NOP_EXPR: /* atomic write */ - case OMP_ATOMIC: memory_order = OMP_MEMORY_ORDER_RELEASE; break; default: @@ -40209,31 +40208,24 @@ cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc) switch (code) { case OMP_ATOMIC_READ: - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL - || memory_order == OMP_MEMORY_ORDER_RELEASE) + if (memory_order == OMP_MEMORY_ORDER_RELEASE) { error_at (loc, "%<#pragma omp atomic read%> incompatible with " - "% or % clauses"); + "% clause"); memory_order = OMP_MEMORY_ORDER_SEQ_CST; } + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) + memory_order = OMP_MEMORY_ORDER_ACQUIRE; break; case NOP_EXPR: /* atomic write */ - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL - || memory_order == OMP_MEMORY_ORDER_ACQUIRE) + if (memory_order == OMP_MEMORY_ORDER_ACQUIRE) { error_at (loc, "%<#pragma omp atomic write%> incompatible with " - "% or % clauses"); - memory_order = OMP_MEMORY_ORDER_SEQ_CST; - } - break; - case OMP_ATOMIC: - if (memory_order == OMP_MEMORY_ORDER_ACQ_REL - || memory_order == OMP_MEMORY_ORDER_ACQUIRE) - { - error_at (loc, "%<#pragma omp atomic update%> incompatible with " - "% or % clauses"); + "% clause"); memory_order = OMP_MEMORY_ORDER_SEQ_CST; } + else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL) + memory_order = OMP_MEMORY_ORDER_RELEASE; break; default: break; 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 From a26206ec7b8f8c60747c25d009ea7f9b94184215 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 11 Sep 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/cp/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 84b9b97..8d1ec5d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2021-09-10 Jakub Jelinek + + * 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. + 2021-09-08 Richard Biener PR c++/102228 -- cgit v1.1 From c8b2b89358481d36755dbc99e585a251780453b0 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Mon, 13 Sep 2021 10:29:32 -0400 Subject: c++: parameter pack inside constexpr if [PR101764] Here when partially instantiating the first pack expansion, substitution into the condition of the constexpr if yields a still-dependent tree, so tsubst_expr returns an IF_STMT with an unsubstituted IF_COND and with IF_STMT_EXTRA_ARGS added to. Hence after partial instantiation the pack expansion pattern still refers to the unlowered parameter pack 'ts' of level 2, and it's thusly recorded in the new PACK_EXPANSION_PARAMETER_PACKS. During the subsequent final instantiation of the regenerated lambda we crash in tsubst_pack_expansion because it can't find an argument pack for this unlowered 'ts', due to the level mismatch. (Likewise when the constexpr if is replaced by a requires-expr, which also uses the extra args mechanism for avoiding partial instantiation.) So essentially, a pack expansion pattern that contains an "extra args" tree doesn't play well with partial instantiation. This patch fixes this by forcing such pack expansions to use the extra args mechanism as well. PR c++/101764 gcc/cp/ChangeLog: * cp-tree.h (PACK_EXPANSION_FORCE_EXTRA_ARGS_P): New accessor macro. * pt.c (has_extra_args_mechanism_p): New function. (find_parameter_pack_data::found_extra_args_tree_p): New data member. (find_parameter_packs_r): Set ppd->found_extra_args_tree_p appropriately. (make_pack_expansion): Set PACK_EXPANSION_FORCE_EXTRA_ARGS_P if ppd.found_extra_args_tree_p. (use_pack_expansion_extra_args_p): Return true if there were unsubstituted packs and PACK_EXPANSION_FORCE_EXTRA_ARGS_P. (tsubst_pack_expansion): Pass the pack expansion to use_pack_expansion_extra_args_p. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/constexpr-if35.C: New test. --- gcc/cp/cp-tree.h | 5 +++++ gcc/cp/pt.c | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) (limited to 'gcc/cp') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ceb5359..a82747c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -493,6 +493,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; CONSTRUCTOR_C99_COMPOUND_LITERAL (in CONSTRUCTOR) OVL_NESTED_P (in OVERLOAD) DECL_MODULE_EXPORT_P (in _DECL) + PACK_EXPANSION_FORCE_EXTRA_ARGS_P (in *_PACK_EXPANSION) 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, CALL_EXPR, or FIELD_DECL). @@ -3903,6 +3904,10 @@ struct GTY(()) lang_decl { /* True iff this pack expansion is for auto... in lambda init-capture. */ #define PACK_EXPANSION_AUTO_P(NODE) TREE_LANG_FLAG_2 (NODE) +/* True if we must use PACK_EXPANSION_EXTRA_ARGS and avoid partial + instantiation of this pack expansion. */ +#define PACK_EXPANSION_FORCE_EXTRA_ARGS_P(NODE) TREE_LANG_FLAG_3 (NODE) + /* True iff the wildcard can match a template parameter pack. */ #define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1b81501..224dd9e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -3855,6 +3855,18 @@ expand_builtin_pack_call (tree call, tree args, tsubst_flags_t complain, return NULL_TREE; } +/* Return true if the tree T has the extra args mechanism for + avoiding partial instantiation. */ + +static bool +has_extra_args_mechanism_p (const_tree t) +{ + return (PACK_EXPANSION_P (t) /* PACK_EXPANSION_EXTRA_ARGS */ + || TREE_CODE (t) == REQUIRES_EXPR /* REQUIRES_EXPR_EXTRA_ARGS */ + || (TREE_CODE (t) == IF_STMT + && IF_STMT_CONSTEXPR_P (t))); /* IF_STMT_EXTRA_ARGS */ +} + /* Structure used to track the progress of find_parameter_packs_r. */ struct find_parameter_pack_data { @@ -3867,6 +3879,9 @@ struct find_parameter_pack_data /* True iff we're making a type pack expansion. */ bool type_pack_expansion_p; + + /* True iff we found a subtree that has the extra args mechanism. */ + bool found_extra_args_tree_p = false; }; /* Identifies all of the argument packs that occur in a template @@ -3968,6 +3983,9 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) *ppd->parameter_packs = tree_cons (NULL_TREE, t, *ppd->parameter_packs); } + if (has_extra_args_mechanism_p (t) && !PACK_EXPANSION_P (t)) + ppd->found_extra_args_tree_p = true; + if (TYPE_P (t)) cp_walk_tree (&TYPE_CONTEXT (t), &find_parameter_packs_r, ppd, ppd->visited); @@ -4229,6 +4247,14 @@ make_pack_expansion (tree arg, tsubst_flags_t complain) PACK_EXPANSION_PARAMETER_PACKS (result) = parameter_packs; PACK_EXPANSION_LOCAL_P (result) = at_function_scope_p (); + if (ppd.found_extra_args_tree_p) + /* If the pattern of this pack expansion contains a subtree that has + the extra args mechanism for avoiding partial instantiation, then + force this pack expansion to also use extra args. Otherwise + partial instantiation of this pack expansion may not lower the + level of some parameter packs within the pattern, which would + confuse tsubst_pack_expansion later (PR101764). */ + PACK_EXPANSION_FORCE_EXTRA_ARGS_P (result) = true; return result; } @@ -12405,10 +12431,15 @@ make_argument_pack_select (tree arg_pack, unsigned index) substitution. */ static bool -use_pack_expansion_extra_args_p (tree parm_packs, +use_pack_expansion_extra_args_p (tree t, + tree parm_packs, int arg_pack_len, bool has_empty_arg) { + if (has_empty_arg + && PACK_EXPANSION_FORCE_EXTRA_ARGS_P (t)) + return true; + /* If one pack has an expansion and another pack has a normal argument or if one pack has an empty argument and an another one hasn't then tsubst_pack_expansion cannot perform the @@ -13161,7 +13192,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, /* We cannot expand this expansion expression, because we don't have all of the argument packs we need. */ - if (use_pack_expansion_extra_args_p (packs, len, unsubstituted_packs)) + if (use_pack_expansion_extra_args_p (t, packs, len, unsubstituted_packs)) { /* We got some full packs, but we can't substitute them in until we have values for all the packs. So remember these until then. */ -- cgit v1.1 From 76b75018b3d053a890ebe155e47814de14b3c9fb Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 15 Jul 2021 15:30:17 -0400 Subject: c++: implement C++17 hardware interference size The last missing piece of the C++17 standard library is the hardware intereference size constants. Much of the delay in implementing these has been due to uncertainty about what the right values are, and even whether there is a single constant value that is suitable; the destructive interference size is intended to be used in structure layout, so program ABIs will depend on it. In principle, both of these values should be the same as the target's L1 cache line size. When compiling for a generic target that is intended to support a range of target CPUs with different cache line sizes, the constructive size should probably be the minimum size, and the destructive size the maximum, unless you are constrained by ABI compatibility with previous code. From discussion on gcc-patches, I've come to the conclusion that the solution to the difficulty of choosing stable values is to give up on it, and instead encourage only uses where ABI stability is unimportant: in particular, uses where the ABI is shared at most between translation units built at the same time with the same flags. To that end, I've added a warning for any use of the constant value of std::hardware_destructive_interference_size in a header or module export. Appropriate uses within a project can disable the warning. A previous iteration of this patch included an -finterference-tune flag to make the value vary with -mtune; this iteration makes that the default behavior, which should be appropriate for all reasonable uses of the variable. The previous default of "stable-ish" seems to me likely to have been more of an attractive nuisance; since we can't promise actual stability, we should instead make proper uses more convenient. JF Bastien's implementation proposal is summarized at https://github.com/itanium-cxx-abi/cxx-abi/issues/74 I implement this by adding new --params for the two sizes. Targets can override these values in targetm.target_option.override() to support a range of values for the generic target; otherwise, both will default to the L1 cache line size. 64 bytes still seems correct for all x86. I'm not sure why he proposed 64/64 for generic 32-bit ARM, since the Cortex A9 has a 32-byte cache line, so I'd think 32/64 would make more sense. He proposed 64/128 for generic AArch64, but since the A64FX now has a 256B cache line, I've changed that to 64/256. Other arch maintainers are invited to set ranges for their generic targets if that seems better than using the default cache line size for both values. With the above choice to reject stability as a goal, getting these values "right" is now just a matter of what we want the default optimization to be, and we can feel free to adjust them as CPUs with different cache lines become more and less common. gcc/ChangeLog: * params.opt: Add destructive-interference-size and constructive-interference-size. * doc/invoke.texi: Document them. * config/aarch64/aarch64.c (aarch64_override_options_internal): Set them. * config/arm/arm.c (arm_option_override): Set them. * config/i386/i386-options.c (ix86_option_override_internal): Set them. gcc/c-family/ChangeLog: * c.opt: Add -Winterference-size. * c-cppbuiltin.c (cpp_atomic_builtins): Add __GCC_DESTRUCTIVE_SIZE and __GCC_CONSTRUCTIVE_SIZE. gcc/cp/ChangeLog: * constexpr.c (maybe_warn_about_constant_value): Complain about std::hardware_destructive_interference_size. (cxx_eval_constant_expression): Call it. * decl.c (cxx_init_decl_processing): Check --param *-interference-size values. libstdc++-v3/ChangeLog: * include/std/version: Define __cpp_lib_hardware_interference_size. * libsupc++/new: Define hardware interference size variables. gcc/testsuite/ChangeLog: * g++.dg/warn/Winterference.H: New file. * g++.dg/warn/Winterference.C: New test. * g++.target/aarch64/interference.C: New test. * g++.target/arm/interference.C: New test. * g++.target/i386/interference.C: New test. --- gcc/cp/constexpr.c | 33 +++++++++++++++++++++++++++++++++ gcc/cp/decl.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) (limited to 'gcc/cp') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 7772fe6..0c2498a 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -6075,6 +6075,37 @@ inline_asm_in_constexpr_error (location_t loc) "% function in C++20"); } +/* We're getting the constant value of DECL in a manifestly constant-evaluated + context; maybe complain about that. */ + +static void +maybe_warn_about_constant_value (location_t loc, tree decl) +{ + static bool explained = false; + if (cxx_dialect >= cxx17 + && warn_interference_size + && !global_options_set.x_param_destruct_interfere_size + && DECL_CONTEXT (decl) == std_node + && id_equal (DECL_NAME (decl), "hardware_destructive_interference_size") + && (LOCATION_FILE (input_location) != main_input_filename + || module_exporting_p ()) + && warning_at (loc, OPT_Winterference_size, "use of %qD", decl) + && !explained) + { + explained = true; + inform (loc, "its value can vary between compiler versions or " + "with different %<-mtune%> or %<-mcpu%> flags"); + inform (loc, "if this use is part of a public ABI, change it to " + "instead use a constant variable you define"); + inform (loc, "the default value for the current CPU tuning " + "is %d bytes", param_destruct_interfere_size); + inform (loc, "you can stabilize this value with %<--param " + "hardware_destructive_interference_size=%d%>, or disable " + "this warning with %<-Wno-interference-size%>", + param_destruct_interfere_size); + } +} + /* Attempt to reduce the expression T to a constant value. On failure, issue diagnostic and return error_mark_node. */ /* FIXME unify with c_fully_fold */ @@ -6219,6 +6250,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = *p; break; } + if (ctx->manifestly_const_eval) + maybe_warn_about_constant_value (loc, t); if (COMPLETE_TYPE_P (TREE_TYPE (t)) && is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false)) { diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index bce62ad..c206502 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4752,6 +4752,38 @@ cxx_init_decl_processing (void) /* Show we use EH for cleanups. */ if (flag_exceptions) using_eh_for_cleanups (); + + /* Check that the hardware interference sizes are at least + alignof(max_align_t), as required by the standard. */ + const int max_align = max_align_t_align () / BITS_PER_UNIT; + if (param_destruct_interfere_size) + { + if (param_destruct_interfere_size < max_align) + error ("%<--param destructive-interference-size=%d%> is less than " + "%d", param_destruct_interfere_size, max_align); + else if (param_destruct_interfere_size < param_l1_cache_line_size) + warning (OPT_Winterference_size, + "%<--param destructive-interference-size=%d%> " + "is less than %<--param l1-cache-line-size=%d%>", + param_destruct_interfere_size, param_l1_cache_line_size); + } + else if (param_l1_cache_line_size >= max_align) + param_destruct_interfere_size = param_l1_cache_line_size; + /* else leave it unset. */ + + if (param_construct_interfere_size) + { + if (param_construct_interfere_size < max_align) + error ("%<--param constructive-interference-size=%d%> is less than " + "%d", param_construct_interfere_size, max_align); + else if (param_construct_interfere_size > param_l1_cache_line_size) + warning (OPT_Winterference_size, + "%<--param constructive-interference-size=%d%> " + "is greater than %<--param l1-cache-line-size=%d%>", + param_construct_interfere_size, param_l1_cache_line_size); + } + else if (param_l1_cache_line_size >= max_align) + param_construct_interfere_size = param_l1_cache_line_size; } /* Enter an abi node in global-module context. returns a cookie to -- cgit v1.1