aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJerry DeLisle <jvdelisle@gcc.gnu.org>2025-09-02 15:58:26 -0700
committerJerry DeLisle <jvdelisle@gcc.gnu.org>2025-09-02 15:58:26 -0700
commit071b4126c613881f4cb25b4e5c39032964827f88 (patch)
tree7ed805786566918630d1d617b1ed8f7310f5fd8e /gcc/cp
parent845d23f3ea08ba873197c275a8857eee7edad996 (diff)
parentcaa1c2f42691d68af4d894a5c3e700ecd2dba080 (diff)
downloadgcc-devel/gfortran-test.zip
gcc-devel/gfortran-test.tar.gz
gcc-devel/gfortran-test.tar.bz2
Merge branch 'master' into gfortran-testdevel/gfortran-test
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog484
-rw-r--r--gcc/cp/call.cc27
-rw-r--r--gcc/cp/class.cc25
-rw-r--r--gcc/cp/constexpr.cc115
-rw-r--r--gcc/cp/constraint.cc6
-rw-r--r--gcc/cp/contracts.cc22
-rw-r--r--gcc/cp/contracts.h98
-rw-r--r--gcc/cp/coroutines.cc1
-rw-r--r--gcc/cp/cp-gimplify.cc1
-rw-r--r--gcc/cp/cp-objcp-common.cc1
-rw-r--r--gcc/cp/cp-trait.def1
-rw-r--r--gcc/cp/cp-tree.def5
-rw-r--r--gcc/cp/cp-tree.h108
-rw-r--r--gcc/cp/cxx-pretty-print.cc23
-rw-r--r--gcc/cp/decl.cc538
-rw-r--r--gcc/cp/decl2.cc9
-rw-r--r--gcc/cp/error.cc23
-rw-r--r--gcc/cp/except.cc10
-rw-r--r--gcc/cp/init.cc43
-rw-r--r--gcc/cp/lambda.cc52
-rw-r--r--gcc/cp/lex.cc57
-rw-r--r--gcc/cp/mangle.cc68
-rw-r--r--gcc/cp/mapper-client.cc46
-rw-r--r--gcc/cp/method.cc36
-rw-r--r--gcc/cp/module.cc44
-rw-r--r--gcc/cp/name-lookup.cc24
-rw-r--r--gcc/cp/name-lookup.h6
-rw-r--r--gcc/cp/parser.cc1108
-rw-r--r--gcc/cp/parser.h6
-rw-r--r--gcc/cp/pt.cc676
-rw-r--r--gcc/cp/search.cc1
-rw-r--r--gcc/cp/semantics.cc191
-rw-r--r--gcc/cp/tree.cc11
-rw-r--r--gcc/cp/typeck.cc33
-rw-r--r--gcc/cp/typeck2.cc89
35 files changed, 3393 insertions, 595 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 08ec840..e32ee1c 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,487 @@
+2025-08-29 Sirui Mu <msrlancern@gmail.com>
+
+ * typeck.cc (cp_build_array_ref): Handle 0[arr] earlier.
+
+2025-08-28 Jason Merrill <jason@redhat.com>
+
+ PR c++/107953
+ * parser.cc (cp_parser_lambda_expression): Set
+ greater_than_is_operator_p.
+
+2025-08-28 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/119844
+ * typeck2.cc (cxx_incomplete_type_inform): Add explanation when
+ a similar type is complete but attached to a different module.
+ Also fix handling of partial specs and templates.
+
+2025-08-28 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/121583
+ * semantics.cc (apply_deduced_return_type): Adjust
+ fun->returns*_struct when !uses_template_parms (fco) instead of
+ when !processing_template_decl.
+
+2025-08-28 Jakub Jelinek <jakub@redhat.com>
+ Jason Merrill <jason@redhat.com>
+
+ PR c++/121575
+ * pt.cc (tsubst_expr) <case PARM_DECL>: If DECL_CONTEXT (t) isn't a
+ template return t for PARM_DECLs without local specialization.
+
+2025-08-26 Sandra Loosemore <sloosemore@baylibre.com>
+
+ PR middle-end/118839
+ * decl.cc (omp_declare_variant_finalize_one): Error if variant
+ is the same as base.
+
+2025-08-26 Sandra Loosemore <sloosemore@baylibre.com>
+
+ * parser.cc (cp_finish_omp_declare_variant): Structure diagnostic
+ code similarly to C front end. Make check for a missing "match"
+ clause unconditional.
+
+2025-08-25 Jakub Jelinek <jakub@redhat.com>
+
+ * pt.cc (finish_expansion_stmt): Implement C++ CWG3048
+ - Empty destructuring expansion statements. Don't error for
+ destructuring expansion stmts if sz is 0, don't call
+ fit_decomposition_lang_decl if n is 0 and pass NULL rather than
+ this_decomp to cp_finish_decl.
+
+2025-08-25 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/121601
+ * constexpr.cc (cxx_bind_parameters_in_call): Move break
+ if *jump_target before the check for null this object pointer.
+
+2025-08-23 Eczbek <eczbek.void@gmail.com>
+
+ PR c++/116928
+ * parser.cc (cp_parser_braced_list): Set greater_than_is_operator_p.
+
+2025-08-23 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120499
+ * method.cc (synthesize_method): Set the instantiating module.
+
+2025-08-21 Jason Merrill <jason@redhat.com>
+
+ PR c++/121068
+ * constexpr.cc (cxx_eval_store_expression): Allow clobber of a const
+ object.
+
+2025-08-21 Jason Merrill <jason@redhat.com>
+
+ PR c++/120757
+ * pt.cc (tsubst_expr) [OFFSET_REF]: Don't tsubst the type.
+
+2025-08-20 Marek Polacek <polacek@redhat.com>
+
+ PR c++/121553
+ * name-lookup.cc (check_local_shadow): Check !is_normal_capture_proxy.
+
+2025-08-19 Ben Wu <soggysocks206@gmail.com>
+
+ PR c++/120618
+ * parser.cc (cp_parser_compound_requirement): Set type to
+ NULL_TREE for invalid type-constraint.
+
+2025-08-19 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/121351
+ * class.cc (add_method): Use outer_template_args when
+ substituting outer template arguments into constraints.
+
+2025-08-19 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120195
+ * name-lookup.cc (do_nonmember_using_decl): Also handle change
+ in exportedness of a function.
+
+2025-08-18 Indu Bhagat <indu.bhagat@oracle.com>
+
+ * typeck.cc (get_member_function_from_ptrfunc): Use
+ 'sanitize_code_type' instead of 'unsigned int'.
+
+2025-08-17 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120503
+ PR c++/120824
+ * cp-tree.h (TYPE_UNNAMED_P): Adjust for enums with enumerators
+ for linkage purposes.
+ (enum_with_enumerator_for_linkage_p): Declare.
+ * decl.cc (name_unnamed_type): Adjust assertions to handle enums
+ with enumerators for linkage purposes.
+ (grokdeclarator): Use a typedef name for enums with enumerators
+ for linkage purposes.
+ (enum_with_enumerator_for_linkage_p): New function.
+ (finish_enum_value_list): Reset type linkage for enums with
+ enumerators for linkage purposes.
+ * mangle.cc (write_unnamed_enum_name): New function.
+ (write_unqualified_name): Handle enums with enumerators for
+ linkage purposes.
+ * tree.cc (decl_linkage): Fixup unnamed enums.
+
+2025-08-15 Jakub Jelinek <jakub@redhat.com>
+
+ * cp-trait.def (STRUCTURED_BINDING_SIZE): New unary trait.
+ * cp-tree.h (finish_structured_binding_size): Declare.
+ * semantics.cc (trait_expr_value): Handle
+ CPTK_STRUCTURED_BINDING_SIZE.
+ (finish_structured_binding_size): New function.
+ (finish_trait_expr): Handle CPTK_RANK and CPTK_TYPE_ORDER
+ in the switch instead of just doing break; for those and
+ ifs at the end to handle them. Handle CPTK_STRUCTURED_BINDING_SIZE.
+ * pt.cc (tsubst_expr): Likewise.
+ * constraint.cc (diagnose_trait_expr): Likewise.
+ * decl.cc (get_tuple_size): Use mce_true for maybe_const_value.
+ (cp_decomp_size): Diagnose incomplete types not just if
+ processing_template_decl, and use error_at instead of pedwarn.
+ If btype is NULL, just return 0 instead of diagnosing an error.
+
+2025-08-15 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/121552
+ * decl.cc: Implement C++20 P1766R1 - Mitigating minor modules maladies.
+ (diagnose_non_c_class_typedef_for_linkage,
+ maybe_diagnose_non_c_class_typedef_for_linkage): New functions.
+ (name_unnamed_type): Call
+ maybe_diagnose_non_c_class_typedef_for_linkage.
+
+2025-08-15 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/121539
+ * parser.cc (cp_parser_cache_defarg): Set done to true for
+ CPP_ELLIPSIS followed by CPP_CLOSE_PAREN in !nsdmi at depth 0.
+
+2025-08-15 Jakub Jelinek <jakub@redhat.com>
+
+ PR preprocessor/120778
+ PR target/121520
+ * lex.cc (cxx_init): Remove warn_on lambda. Use cpp_warn instead of
+ cpp_lookup and NODE_WARN bit setting or warn_on.
+
+2025-08-14 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/121524
+ * tree.cc (build_cplus_array_type): Don't reuse variant type
+ if it has TREE_DEPRECATED or TREE_UNAVAILABLE flags set or,
+ unless elt_type has TYPE_USER_ALIGN set and TYPE_ALIGN is
+ TYPE_ALIGN of elt_type, TYPE_USER_ALIGN is not set.
+
+2025-08-13 Marek Polacek <polacek@redhat.com>
+
+ PR c++/102610
+ * cp-tree.h (LAMBDA_EXPR_CONST_QUAL_P): Define.
+ (maybe_add_dummy_lambda_op): Declare.
+ (remove_dummy_lambda_op): Declare.
+ (push_capture_proxies): Adjust.
+ * lambda.cc (build_capture_proxy): No longer static. New early_p
+ parameter. Use it.
+ (add_capture): Adjust the call to build_capture_proxy.
+ (resolvable_dummy_lambda): Check DECL_LAMBDA_FUNCTION_P.
+ (push_capture_proxies): New.
+ (start_lambda_function): Use it.
+ * name-lookup.cc (check_local_shadow): Give an error for
+ is_capture_proxy.
+ (cp_binding_level_descriptor): Add lambda-scope.
+ (begin_scope) <case sk_lambda>: New case.
+ * name-lookup.h (enum scope_kind): Add sk_lambda.
+ (struct cp_binding_level): Widen kind.
+ * parser.cc (cp_parser_lambda_expression): Create a new (lambda) scope
+ after the lambda-introducer.
+ (cp_parser_lambda_declarator_opt): Set LAMBDA_EXPR_CONST_QUAL_P.
+ Create a dummy operator() if needed. Inject the captures into the
+ lambda scope. Remove the dummy operator().
+ (make_dummy_lambda_op): New.
+ (maybe_add_dummy_lambda_op): New.
+ (remove_dummy_lambda_op): New.
+ * pt.cc (tsubst_lambda_expr): Begin/end a lambda scope. Push the
+ capture proxies. Build/remove a dummy operator() if needed. Set
+ LAMBDA_EXPR_CONST_QUAL_P.
+ * semantics.cc (parsing_lambda_declarator): New.
+ (outer_var_p): Also consider captures as outer variables if in a lambda
+ declarator.
+ (process_outer_var_ref): Reset containing_function when
+ parsing_lambda_declarator.
+ (finish_decltype_type): Process decls in the lambda-declarator as well.
+ Look at LAMBDA_EXPR_CONST_QUAL_P unless we have an xobj function.
+
+2025-08-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/120776
+ * cp-tree.def: Implement C++26 P1306R5 - Expansion statements.
+ (TEMPLATE_FOR_STMT): New tree code.
+ * cp-tree.h (struct saved_scope): Add expansion_stmt.
+ (in_expansion_stmt): Define.
+ (TEMPLATE_FOR_DECL, TEMPLATE_FOR_EXPR, TEMPLATE_FOR_BODY,
+ TEMPLATE_FOR_SCOPE, TEMPLATE_FOR_INIT_STMT): Define.
+ (struct tinst_level): Adjust comment.
+ (cp_decomp_size, finish_expansion_stmt, do_pushlevel,
+ cp_build_range_for_decls, build_range_temp,
+ cp_perform_range_for_lookup, begin_template_for_scope): Declare.
+ (finish_range_for_stmt): Remove declaration.
+ * cp-objcp-common.cc (cp_common_init_ts): Handle TEMPLATE_FOR_STMT.
+ * name-lookup.h (enum scope_kind): Add sk_template_for enumerator.
+ (struct cp_binding_level): Enlarge kind bitfield from 4 to 5 bits.
+ Adjust comment with remaining space bits.
+ * name-lookup.cc (check_local_shadow): Handle sk_template_for like
+ sk_for.
+ (cp_binding_level_descriptor): Add entry for sk_template_for.
+ (begin_scope): Handle sk_template_for.
+ * parser.h (IN_EXPANSION_STMT): Define.
+ * parser.cc (cp_debug_parser): Print IN_EXPANSION_STMT bit.
+ (cp_parser_lambda_expression): Temporarily clear in_expansion_stmt.
+ (cp_parser_statement): Handle RID_TEMPLATE followed by RID_FOR for
+ C++11.
+ (cp_parser_label_for_labeled_statement): Complain about named labels
+ inside of expansion stmt body.
+ (cp_hide_range_decl): New function.
+ (cp_parser_range_for): Use it. Adjust do_range_for_auto_deduction
+ caller. Remove second template argument from auto_vecs bindings and
+ names.
+ (build_range_temp): No longer static.
+ (do_range_for_auto_deduction): Add expansion_stmt argument.
+ (cp_build_range_for_decls): New function.
+ (cp_convert_range_for): Use it. Call cp_perform_range_for_lookup
+ rather than cp_parser_perform_range_for_lookup.
+ (cp_parser_perform_range_for_lookup): Rename to ...
+ (cp_perform_range_for_lookup): ... this. No longer static. Add
+ complain argument and handle it.
+ (cp_parser_range_for_member_function): Rename to ...
+ (cp_range_for_member_function): ... this.
+ (cp_parser_expansion_statement): New function.
+ (cp_parser_jump_statement): Handle IN_EXPANSION_STMT.
+ (cp_convert_omp_range_for): Adjust do_range_for_auto_deduction caller.
+ Call cp_perform_range_for_lookup rather than
+ cp_parser_perform_range_for_lookup.
+ * error.cc (print_instantiation_full_context): Handle tldcl being
+ TEMPLATE_FOR_STMT.
+ (print_instantiation_partial_context_line): Likewise.
+ * constexpr.cc (potential_constant_expression_1): Handle
+ TEMPLATE_FOR_STMT.
+ * decl.cc (poplevel_named_label_1): Use obl instead of bl->level_chain.
+ (finish_case_label): Diagnose case labels inside of template for.
+ (find_decomp_class_base): Add complain argument, don't diagnose
+ anything and just return error_mark_node if tf_none, adjust recursive
+ call.
+ (cp_decomp_size): New function.
+ (cp_finish_decomp): Adjust find_decomp_class_base caller.
+ * semantics.cc (do_pushlevel): No longer static.
+ (begin_template_for_scope): New function.
+ * pt.cc (push_tinst_level_loc): Handle TEMPLATE_FOR_STMT.
+ (reopen_tinst_level): Likewise.
+ (tsubst_stmt): Handle TEMPLATE_FOR_STMT.
+ (struct expansion_stmt_bc): New type.
+ (expansion_stmt_find_bc_r, finish_expansion_stmt): New functions.
+ * decl2.cc (decl_dependent_p): Return true for current function's decl
+ if in_expansion_stmt.
+ * call.cc (extend_ref_init_temps): Don't extend_all_temps if
+ TREE_STATIC (decl).
+ * cxx-pretty-print.cc (cxx_pretty_printer::statement): Handle
+ TEMPLATE_FOR_STMT.
+
+2025-08-13 Benjamin Wu <bwu25@cs.washington.edu>
+
+ * lex.cc (init_operators): Fix typo.
+
+2025-08-11 Nicolas Werner <nicolas.werner@hotmail.de>
+
+ * mapper-client.cc (spawn_mapper_program): change argv parsing
+
+2025-08-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/117783
+ * decl.cc (set_sb_pack_name): For name independent decls
+ just clear DECL_NAME instead of appending #i to it.
+
+2025-08-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/117783
+ * decl.cc (cp_finish_decomp): Don't sorry on tuple static
+ structured bindings with a pack, instead temporarily reset
+ DECL_NAME of the individual vars in the pack to the name
+ of the pack for cp_finish_decl time and force mangling.
+
+2025-08-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/121442
+ * parser.cc (cp_parser_decomposition_declaration): Don't copy
+ DECL_DECLARED_CONST{EXPR,INIT}_P bits from decl to decl2 if
+ decl is error_mark_node.
+
+2025-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ * error.cc (cp_adjust_diagnostic_info): Convert "context" arg from
+ ptr to const &.
+
+2025-08-07 Patrick Palka <ppalka@redhat.com>
+
+ * call.cc (extract_call_expr): Remove handling of C++20
+ rewritten comparison operators.
+
+2025-08-07 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/117783
+ * parser.cc: Implement C++26 P1061R10 - Structured Bindings can
+ introduce a Pack.
+ (cp_parser_range_for): Also handle TREE_VEC as DECL_VALUE_EXPR
+ instead of ARRAY_REF.
+ (cp_parser_decomposition_declaration): Use sb-identifier-list instead
+ of identifier-list in comments. Parse structured bindings with
+ structured binding pack. Don't emit pedwarn about structured
+ binding attributes in structured bindings inside of a condition.
+ (cp_convert_omp_range_for): Also handle TREE_VEC as DECL_VALUE_EXPR
+ instead of ARRAY_REF.
+ * decl.cc (get_tuple_element_type): Change i argument type from
+ unsigned to unsigned HOST_WIDE_INT.
+ (get_tuple_decomp_init): Likewise.
+ (set_sb_pack_name): New function.
+ (cp_finish_decomp): Handle structured binding packs.
+ * pt.cc (tsubst_pack_expansion): Handle structured binding packs
+ and capture proxies for them. Formatting fixes.
+ (tsubst_decl): For structured binding packs don't tsubst TREE_TYPE
+ first, instead recreate the type after r is created.
+ (tsubst_omp_for_iterator): Also handle TREE_VEC as DECL_VALUE_EXPR
+ instead of ARRAY_REF.
+ (tsubst_expr): Handle sizeof... on non-dependent structure binding
+ packs.
+ (value_dependent_expression_p): Return false for sizeof... on
+ non-dependent structure binding packs.
+ (instantiation_dependent_r): Don't recurse on sizeof... on
+ non-dependent structure binding packs.
+ * constexpr.cc (potential_constant_expression_1): Also handle
+ TREE_VEC on DECL_VALUE_EXPR of structure binding packs.
+
+2025-08-07 Jakub Jelinek <jakub@redhat.com>
+
+ PR preprocessor/120778
+ * lex.cc (cxx_init): Mark cpp nodes corresponding
+ to keywords, identifiers with special meaning and standard
+ attribute identifiers as NODE_WARN if warn_keyword_macro.
+
+2025-08-06 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/121231
+ PR c++/119688
+ PR c++/94511
+ * mangle.cc (write_expression): Write out implicit non-trailing
+ zeroes of a CONSTRUCTOR when the ABI version is at least 21.
+
+2025-08-06 Jason Merrill <jason@redhat.com>
+
+ * constexpr.cc (cxx_eval_indirect_ref): Improve diagnostic.
+
+2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com>
+
+ * parser.cc (cp_parser_omp_clause_from_to): Parse 'iterator' modifier.
+ * semantics.cc (finish_omp_clauses): Finish iterators for to/from
+ clauses.
+
+2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com>
+ Andrew Stubbs <ams@baylibre.com>
+
+ * parser.cc (cp_parser_omp_clause_map): Parse 'iterator' modifier.
+ * semantics.cc (finish_omp_clauses): Finish iterators. Apply
+ iterators to generated clauses.
+
+2025-08-05 Jason Merrill <jason@redhat.com>
+
+ PR c++/121068
+ * constexpr.cc (cxx_eval_store_expression): Handle clobbers.
+ (potential_constant_expression_1): Handle clobbers more.
+ * decl.cc (build_clobber_this): Use INIT_EXPR for initial clobber.
+ * init.cc (build_new_1): Clobber on placement new.
+ (build_vec_init): Don't clean up after clobber.
+
+2025-08-04 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/121351
+ PR c++/119859
+ * class.cc (add_method): Substitute outer template arguments
+ into constraints before comparing them if the declarations are
+ from different classes.
+
+2025-08-04 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/120620
+ * constexpr.cc (cxx_dynamic_cast_fn_p): Return true only
+ for synthesized __dynamic_cast.
+
+2025-08-01 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/108080
+ * module.cc (trees_out::core_vals): Warn when streaming
+ target/optimize node; adjust comments.
+ (trees_in::core_vals): Don't stream a target/optimize node.
+
+2025-08-01 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/121238
+ * module.cc (trees_in::fn_parms_fini): Merge properties for
+ definitions.
+
+2025-07-31 Jason Merrill <jason@redhat.com>
+
+ PR c++/120800
+ * constexpr.cc (cxx_eval_vec_init_1): Suppress access control.
+
+2025-07-31 Marek Polacek <polacek@redhat.com>
+
+ PR c++/120775
+ * constexpr.cc (cxx_eval_outermost_constant_expr): Use
+ extract_call_expr.
+ * cp-tree.h (CONSTEVAL_BLOCK_P, LAMBDA_EXPR_CONSTEVAL_BLOCK_P): Define.
+ (finish_static_assert): Adjust declaration.
+ (current_nonlambda_function): Likewise.
+ * lambda.cc (current_nonlambda_function): New parameter. Only keep
+ iterating if the function represents a consteval block.
+ * parser.cc (cp_parser_lambda_expression): New parameter for
+ consteval blocks. Use it. Set LAMBDA_EXPR_CONSTEVAL_BLOCK_P.
+ (cp_parser_lambda_declarator_opt): Likewise.
+ (build_empty_string): New.
+ (cp_parser_next_tokens_are_consteval_block_p): New.
+ (cp_parser_consteval_block): New.
+ (cp_parser_block_declaration): Handle consteval blocks.
+ (cp_parser_static_assert): Use build_empty_string.
+ (cp_parser_member_declaration): Handle consteval blocks.
+ * pt.cc (tsubst_stmt): Adjust a call to finish_static_assert.
+ * semantics.cc (finish_fname): Warn for consteval blocks.
+ (finish_static_assert): New parameter for consteval blocks. Set
+ CONSTEVAL_BLOCK_P. Evaluate consteval blocks specially.
+
+2025-07-30 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/121291
+ * constraint.cc (diagnose_trait_expr): Remove assumption about
+ failures returning error_mark_node.
+ * except.cc (explain_not_noexcept): Allow expr not being
+ noexcept.
+ * method.cc (build_invoke): Adjust comment.
+ (is_trivially_xible): Always note non-trivial components if expr
+ is not null or error_mark_node.
+ (is_nothrow_xible): Likewise for non-noexcept components.
+ (is_nothrow_convertible): Likewise.
+
+2025-07-30 Jason Merrill <jason@redhat.com>
+
+ * pt.cc (convert_nontype_argument_function): Check
+ cxx_constant_value on failure.
+ (invalid_tparm_referent_p): Likewise.
+
+2025-07-30 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/121133
+ * parser.cc (cp_parser_unary_expression): Adjust
+ cp_parser_extension_opt caller and restore warn_long_long.
+ (cp_parser_declaration): Likewise.
+ (cp_parser_block_declaration): Likewise.
+ (cp_parser_member_declaration): Likewise.
+ (cp_parser_extension_opt): Add SAVED_LONG_LONG argument,
+ save previous warn_long_long state into it and clear it
+ for __extension__.
+
2025-07-27 Nathaniel Shead <nathanieloshead@gmail.com>
* cp-tree.h (struct lang_type): Add comment mentioning modules.
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 9283d97..02cef63 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -7904,28 +7904,6 @@ extract_call_expr (tree call)
call = TREE_OPERAND (call, 0);
if (TREE_CODE (call) == TARGET_EXPR)
call = TARGET_EXPR_INITIAL (call);
- if (cxx_dialect >= cxx20)
- switch (TREE_CODE (call))
- {
- /* C++20 rewritten comparison operators. */
- case TRUTH_NOT_EXPR:
- call = TREE_OPERAND (call, 0);
- break;
- case LT_EXPR:
- case LE_EXPR:
- case GT_EXPR:
- case GE_EXPR:
- case SPACESHIP_EXPR:
- {
- tree op0 = TREE_OPERAND (call, 0);
- if (integer_zerop (op0))
- call = TREE_OPERAND (call, 1);
- else
- call = op0;
- }
- break;
- default:;
- }
if (TREE_CODE (call) != CALL_EXPR
&& TREE_CODE (call) != AGGR_INIT_EXPR
@@ -15054,7 +15032,10 @@ extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups,
/* P2718R0 - in C++23 for-range-initializer, extend all temps. */
if (DECL_NAME (decl) == for_range__identifier
- && flag_range_for_ext_temps)
+ && flag_range_for_ext_temps
+ /* Iterating expansion statement decl is static right now, but that
+ could change depending on CWG3044 and CWG3043. */
+ && !TREE_STATIC (decl))
{
gcc_checking_assert (!cond_guard);
return extend_all_temps (decl, init, cleanups);
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index f5d20e5..cf58f65 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -1356,7 +1356,30 @@ add_method (tree type, tree method, bool via_using)
if (!compparms (parms1, parms2))
continue;
- if (!equivalently_constrained (fn, method))
+ tree fn_constraints = get_constraints (fn);
+ tree method_constraints = get_constraints (method);
+
+ if (fn_constraints && method_constraints
+ && DECL_CONTEXT (fn) != type
+ && !processing_template_decl)
+ {
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
+ ++processing_template_decl;
+ if (tree outer_args = outer_template_args (fn))
+ fn_constraints = tsubst_constraint_info (fn_constraints,
+ outer_args,
+ tf_warning_or_error,
+ fn);
+ if (tree outer_args = outer_template_args (method))
+ method_constraints = tsubst_constraint_info (method_constraints,
+ outer_args,
+ tf_warning_or_error,
+ method);
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
+ --processing_template_decl;
+ }
+
+ if (!equivalent_constraints (fn_constraints, method_constraints))
{
if (processing_template_decl)
/* We can't check satisfaction in dependent context, wait until
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index f92beb1..c3d0524 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see
#include "fold-const.h"
#include "intl.h"
#include "toplev.h"
+#include "contracts.h"
static bool verify_constant (tree, bool, bool *, bool *);
#define VERIFY_CONSTANT(X) \
@@ -2694,6 +2695,8 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
arg = cxx_eval_constant_expression (ctx, x, vc_prvalue,
non_constant_p, overflow_p,
jump_target);
+ if (*jump_target)
+ break;
/* Check we aren't dereferencing a null pointer when calling a non-static
member function, which is undefined behaviour. */
if (i == 0 && DECL_OBJECT_MEMBER_FUNCTION_P (fun)
@@ -2711,8 +2714,6 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
/* Don't VERIFY_CONSTANT here. */
if (*non_constant_p && ctx->quiet)
break;
- if (*jump_target)
- break;
/* Just discard ellipsis args after checking their constantitude. */
if (!parms)
continue;
@@ -3240,7 +3241,11 @@ cxx_dynamic_cast_fn_p (tree fndecl)
{
return (cxx_dialect >= cxx20
&& id_equal (DECL_NAME (fndecl), "__dynamic_cast")
- && CP_DECL_CONTEXT (fndecl) == abi_node);
+ && CP_DECL_CONTEXT (fndecl) == abi_node
+ /* Only consider implementation-detail __dynamic_cast calls that
+ correspond to a dynamic_cast, and ignore direct calls to
+ abi::__dynamic_cast. */
+ && DECL_ARTIFICIAL (fndecl));
}
/* Often, we have an expression in the form of address + offset, e.g.
@@ -6598,6 +6603,9 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
return cxx_eval_bare_aggregate (ctx, init, lval,
non_constant_p, overflow_p, jump_target);
+ /* We already checked access when building the VEC_INIT_EXPR. */
+ deferring_access_check_sentinel acs (dk_deferred);
+
/* For the default constructor, build up a call to the default
constructor of the element type. We only need to handle class types
here, as for a constructor to be constexpr, all members must be
@@ -7172,10 +7180,23 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
(TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t)));
/* DR 1188 says we don't have to deal with this. */
if (!ctx->quiet)
- error_at (cp_expr_loc_or_input_loc (t),
- "accessing value of %qE through a %qT glvalue in a "
- "constant expression", build_fold_indirect_ref (sub),
- TREE_TYPE (t));
+ {
+ auto_diagnostic_group d;
+ error_at (cp_expr_loc_or_input_loc (t),
+ "accessing value of %qT object through a %qT "
+ "glvalue in a constant expression",
+ TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t));
+ tree ob = build_fold_indirect_ref (sub);
+ if (DECL_P (ob))
+ {
+ if (DECL_ARTIFICIAL (ob))
+ inform (DECL_SOURCE_LOCATION (ob),
+ "%qT object created here", TREE_TYPE (ob));
+ else
+ inform (DECL_SOURCE_LOCATION (ob),
+ "%q#D declared here", ob);
+ }
+ }
*non_constant_p = true;
return t;
}
@@ -7445,12 +7466,6 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
tree init = TREE_OPERAND (t, 1);
- if (TREE_CLOBBER_P (init)
- && CLOBBER_KIND (init) < CLOBBER_OBJECT_END)
- /* Only handle clobbers ending the lifetime of objects.
- ??? We should probably set CONSTRUCTOR_NO_CLEARING. */
- return void_node;
-
/* First we figure out where we're storing to. */
tree target = TREE_OPERAND (t, 0);
@@ -7637,11 +7652,17 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
}
/* Handle explicit end-of-lifetime. */
- if (TREE_CLOBBER_P (init))
+ if (TREE_CLOBBER_P (init)
+ && CLOBBER_KIND (init) >= CLOBBER_OBJECT_END)
{
if (refs->is_empty ())
- ctx->global->destroy_value (object);
- return void_node;
+ {
+ ctx->global->destroy_value (object);
+ return void_node;
+ }
+
+ /* Ending the lifetime of a const object is OK. */
+ const_object_being_modified = NULL_TREE;
}
type = TREE_TYPE (object);
@@ -7778,6 +7799,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
*non_constant_p = true;
}
else if (!is_access_expr
+ || (TREE_CLOBBER_P (init)
+ && CLOBBER_KIND (init) >= CLOBBER_OBJECT_END)
|| (TREE_CODE (t) == MODIFY_EXPR
&& CLASS_TYPE_P (inner)
&& !type_has_non_deleted_trivial_default_ctor (inner)))
@@ -7841,11 +7864,17 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
type = reftype;
}
+ /* Change an "as-base" clobber to the real type;
+ we don't need to worry about padding in constexpr. */
+ tree itype = initialized_type (init);
+ if (IS_FAKE_BASE_TYPE (itype))
+ itype = TYPE_CONTEXT (itype);
+
/* For initialization of an empty base, the original target will be
*(base*)this, evaluation of which resolves to the object
argument, which has the derived type rather than the base type. */
if (!empty_base && !(same_type_ignoring_top_level_qualifiers_p
- (initialized_type (init), type)))
+ (itype, type)))
{
gcc_assert (is_empty_class (TREE_TYPE (target)));
empty_base = true;
@@ -7952,8 +7981,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
/* Don't share a CONSTRUCTOR that might be changed later. */
init = unshare_constructor (init);
- gcc_checking_assert (!*valp || (same_type_ignoring_top_level_qualifiers_p
- (TREE_TYPE (*valp), type)));
+ gcc_checking_assert (!*valp
+ || *valp == void_node
+ || (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (*valp), type)));
if (empty_base)
{
/* Just evaluate the initializer and return, since there's no actual data
@@ -7966,6 +7997,22 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
CONSTRUCTOR_ZERO_PADDING_BITS (*valp) = zero_padding_bits;
}
}
+ else if (TREE_CLOBBER_P (init))
+ {
+ if (AGGREGATE_TYPE_P (type))
+ {
+ if (*valp)
+ CONSTRUCTOR_ELTS (*valp) = nullptr;
+ else
+ *valp = build_constructor (type, nullptr);
+ TREE_CONSTANT (*valp) = true;
+ TREE_SIDE_EFFECTS (*valp) = false;
+ CONSTRUCTOR_NO_CLEARING (*valp) = true;
+ CONSTRUCTOR_ZERO_PADDING_BITS (*valp) = zero_padding_bits;
+ }
+ else
+ *valp = void_node;
+ }
else if (*valp && TREE_CODE (*valp) == CONSTRUCTOR
&& TREE_CODE (init) == CONSTRUCTOR)
{
@@ -7990,6 +8037,9 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
&& TREE_CODE (*valp) == CONSTRUCTOR
&& TYPE_READONLY (type))
{
+ tree target_type = TREE_TYPE (target);
+ if (IS_FAKE_BASE_TYPE (target_type))
+ target_type = TYPE_CONTEXT (target_type);
if (INDIRECT_REF_P (target)
&& (is_this_parameter
(tree_strip_nop_conversions (TREE_OPERAND (target, 0)))))
@@ -7997,7 +8047,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
constructor of a delegating constructor). Leave it up to the
caller that set 'this' to set TREE_READONLY appropriately. */
gcc_checking_assert (same_type_ignoring_top_level_qualifiers_p
- (TREE_TYPE (target), type) || empty_base);
+ (target_type, type) || empty_base);
else
TREE_READONLY (*valp) = true;
}
@@ -10329,11 +10379,14 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
{
if (cxx_dialect < cxx20)
return t;
- if (TREE_CODE (t) != CALL_EXPR && TREE_CODE (t) != AGGR_INIT_EXPR)
+ /* We could have a COMPOUND_EXPR here coming from
+ keep_unused_object_arg. */
+ tree x = extract_call_expr (t);
+ if (x == NULL_TREE || x == error_mark_node)
return t;
/* Calls to immediate functions returning void need to be
evaluated. */
- tree fndecl = cp_get_callee_fndecl_nofold (t);
+ tree fndecl = cp_get_callee_fndecl_nofold (x);
if (fndecl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (fndecl))
return t;
else
@@ -11298,6 +11351,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
&& !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (t))
&& !NULLPTR_TYPE_P (TREE_TYPE (t)))
{
+ if (TREE_CLOBBER_P (t))
+ {
+ /* We should have caught any clobbers in INIT/MODIFY_EXPR. */
+ gcc_checking_assert (false);
+ return true;
+ }
+
if (flags & tf_error)
constexpr_error (loc, fundef_p, "lvalue-to-rvalue conversion of "
"a volatile lvalue %qE with type %qT", t,
@@ -11559,12 +11619,14 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
}
return false;
}
+ tree ve = DECL_VALUE_EXPR (t);
/* Treat __PRETTY_FUNCTION__ inside a template function as
potentially-constant. */
- else if (DECL_PRETTY_FUNCTION_P (t)
- && DECL_VALUE_EXPR (t) == error_mark_node)
+ if (DECL_PRETTY_FUNCTION_P (t) && ve == error_mark_node)
return true;
- return RECUR (DECL_VALUE_EXPR (t), rval);
+ if (DECL_DECOMPOSITION_P (t) && TREE_CODE (ve) == TREE_VEC)
+ return RECUR (TREE_VEC_ELT (ve, 0), rval);
+ return RECUR (ve, rval);
}
if (want_rval
&& (now || !var_in_maybe_constexpr_fn (t))
@@ -12121,6 +12183,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
}
/* FALLTHRU */
case INIT_EXPR:
+ if (TREE_CLOBBER_P (TREE_OPERAND (t, 1)))
+ return true;
return RECUR (TREE_OPERAND (t, 1), rval);
case CONSTRUCTOR:
@@ -12415,6 +12479,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
case CO_AWAIT_EXPR:
case CO_YIELD_EXPR:
case CO_RETURN_EXPR:
+ case TEMPLATE_FOR_STMT:
if (flags & tf_error)
constexpr_error (cp_expr_loc_or_loc (t, input_location), fundef_p,
"%qE is not a constant expression", t);
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index d4a83e4..4b20b79 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3176,8 +3176,7 @@ diagnose_trait_expr (location_t loc, tree expr, tree args)
inform (loc, "%qT is not invocable, because", t1);
else
inform (loc, "%qT is not invocable by %qT, because", t1, t2);
- tree call = build_invoke (t1, t2, tf_error);
- gcc_assert (call == error_mark_node);
+ build_invoke (t1, t2, tf_error);
}
break;
case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -3305,6 +3304,9 @@ diagnose_trait_expr (location_t loc, tree expr, tree args)
case CPTK_TYPE_ORDER:
inform (loc, "%qT and %qT cannot be ordered", t1, t2);
break;
+ case CPTK_STRUCTURED_BINDING_SIZE:
+ inform (loc, "%qT is not destructurable", t1);
+ break;
case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
inform (loc, "%qT is not a reference that binds to a temporary "
"object of type %qT (direct-initialization)", t1, t2);
diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index d0cfd2e..042524d 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -159,7 +159,7 @@ bool valid_configs[CCS_MAYBE + 1][CCS_MAYBE + 1] = {
{ 0, 1, 0, 0, 1, },
};
-void
+static void
validate_contract_role (contract_role *role)
{
gcc_assert (role);
@@ -171,7 +171,7 @@ validate_contract_role (contract_role *role)
"the %<default%> semantic");
}
-contract_semantic
+static contract_semantic
lookup_concrete_semantic (const char *name)
{
if (strcmp (name, "ignore") == 0)
@@ -210,7 +210,9 @@ role_name_equal (contract_role *role, const char *name)
return role_name_equal (role->name, name);
}
-contract_role *
+static void setup_default_contract_role (bool update = true);
+
+static contract_role *
get_contract_role (const char *name)
{
for (int i = 0; i < max_custom_roles; ++i)
@@ -227,12 +229,12 @@ get_contract_role (const char *name)
return NULL;
}
-contract_role *
+static contract_role *
add_contract_role (const char *name,
contract_semantic des,
contract_semantic aus,
contract_semantic axs,
- bool update)
+ bool update = true)
{
for (int i = 0; i < max_custom_roles; ++i)
{
@@ -271,7 +273,7 @@ get_concrete_axiom_semantic ()
return flag_contract_assumption_mode ? CCS_ASSUME : CCS_IGNORE;
}
-void
+static void
setup_default_contract_role (bool update)
{
contract_semantic check = get_concrete_check ();
@@ -491,6 +493,14 @@ handle_OPT_fcontract_semantic_ (const char *arg)
validate_contract_role (role);
}
+/* Returns the default role. */
+
+static contract_role *
+get_default_contract_role ()
+{
+ return get_contract_role ("default");
+}
+
/* Convert a contract CONFIG into a contract_mode. */
static contract_mode
diff --git a/gcc/cp/contracts.h b/gcc/cp/contracts.h
index 7d955f7..ead07d1 100644
--- a/gcc/cp/contracts.h
+++ b/gcc/cp/contracts.h
@@ -131,38 +131,20 @@ struct contract_mode
} u;
};
-extern contract_role *get_contract_role (const char *);
-extern contract_role *add_contract_role (const char *,
- contract_semantic,
- contract_semantic,
- contract_semantic,
- bool = true);
-extern void validate_contract_role (contract_role *);
-extern void setup_default_contract_role (bool = true);
-extern contract_semantic lookup_concrete_semantic (const char *);
-
/* Map a source level semantic or level name to its value, or invalid. */
extern contract_semantic map_contract_semantic (const char *);
extern contract_level map_contract_level (const char *);
/* Check if an attribute is a cxx contract attribute. */
-extern bool cxx_contract_attribute_p (const_tree);
-extern bool cp_contract_assertion_p (const_tree);
-
-/* Returns the default role. */
-
-inline contract_role *
-get_default_contract_role ()
-{
- return get_contract_role ("default");
-}
+extern bool cxx_contract_attribute_p (const_tree);
+extern bool cp_contract_assertion_p (const_tree);
/* Handle various command line arguments related to semantic mapping. */
-extern void handle_OPT_fcontract_build_level_ (const char *);
+extern void handle_OPT_fcontract_build_level_ (const char *);
extern void handle_OPT_fcontract_assumption_mode_ (const char *);
extern void handle_OPT_fcontract_continuation_mode_ (const char *);
-extern void handle_OPT_fcontract_role_ (const char *);
-extern void handle_OPT_fcontract_semantic_ (const char *);
+extern void handle_OPT_fcontract_role_ (const char *);
+extern void handle_OPT_fcontract_semantic_ (const char *);
enum contract_matching_context
{
@@ -277,29 +259,79 @@ enum contract_matching_context
#define DECL_IS_POST_FN_P(NODE) \
(DECL_ABSTRACT_ORIGIN (NODE) && DECL_POST_FN (DECL_ABSTRACT_ORIGIN (NODE)) == NODE)
+/* contracts.cc */
+extern void emit_assertion (tree);
+
extern void remove_contract_attributes (tree);
+extern bool all_attributes_are_contracts_p (tree);
+extern tree finish_contract_attribute (tree, tree);
extern void copy_contract_attributes (tree, tree);
+extern bool diagnose_misapplied_contracts (tree);
extern void remap_contracts (tree, tree, tree, bool);
+extern tree splice_out_contracts (tree);
+extern void inherit_base_contracts (tree, tree);
+
+extern tree make_postcondition_variable (cp_expr);
+extern tree make_postcondition_variable (cp_expr, tree);
extern void maybe_update_postconditions (tree);
extern void rebuild_postconditions (tree);
extern bool check_postcondition_result (tree, tree, location_t);
-extern tree get_precondition_function (tree);
-extern tree get_postcondition_function (tree);
+
+extern tree grok_contract (tree, tree, tree, cp_expr,
+ location_t);
+extern tree finish_contract_condition (cp_expr);
+extern void update_late_contract (tree, tree, tree);
+extern tree invalidate_contract (tree);
extern void duplicate_contracts (tree, tree);
+
extern void match_deferred_contracts (tree);
extern void defer_guarded_contract_match (tree, tree, tree);
-extern bool diagnose_misapplied_contracts (tree);
-extern tree finish_contract_attribute (tree, tree);
-extern tree invalidate_contract (tree);
-extern void update_late_contract (tree, tree, tree);
-extern tree splice_out_contracts (tree);
-extern bool all_attributes_are_contracts_p (tree);
-extern void inherit_base_contracts (tree, tree);
+
+extern tree get_precondition_function (tree);
+extern tree get_postcondition_function (tree);
extern void start_function_contracts (tree);
extern void maybe_apply_function_contracts (tree);
extern void finish_function_contracts (tree);
extern void set_contract_functions (tree, tree, tree);
+
extern tree build_contract_check (tree);
-extern void emit_assertion (tree);
+
+/* Return the first contract in ATTRS, or NULL_TREE if there are none. */
+
+inline tree
+find_contract (tree attrs)
+{
+ while (attrs && !cxx_contract_attribute_p (attrs))
+ attrs = TREE_CHAIN (attrs);
+ return attrs;
+}
+
+inline void
+set_decl_contracts (tree decl, tree contract_attrs)
+{
+ remove_contract_attributes (decl);
+ DECL_ATTRIBUTES (decl) = chainon (DECL_ATTRIBUTES (decl), contract_attrs);
+}
+
+/* Returns the computed semantic of the node. */
+
+inline contract_semantic
+get_contract_semantic (const_tree t)
+{
+ return (contract_semantic) (TREE_LANG_FLAG_3 (CONTRACT_CHECK (t))
+ | (TREE_LANG_FLAG_2 (t) << 1)
+ | (TREE_LANG_FLAG_0 ((t)) << 2));
+}
+
+/* Sets the computed semantic of the node. */
+
+inline void
+set_contract_semantic (tree t, contract_semantic semantic)
+{
+ TREE_LANG_FLAG_3 (CONTRACT_CHECK (t)) = semantic & 0x01;
+ TREE_LANG_FLAG_2 (t) = (semantic & 0x02) >> 1;
+ TREE_LANG_FLAG_0 (t) = (semantic & 0x04) >> 2;
+}
+
#endif /* ! GCC_CP_CONTRACT_H */
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 690e510..af1c4bc 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see
#include "gcc-rich-location.h"
#include "hash-map.h"
#include "coroutines.h"
+#include "contracts.h"
/* ================= Debug. ================= */
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 4ff8f36a..39da4ff 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "omp-general.h"
#include "opts.h"
#include "gcc-urlifier.h"
+#include "contracts.h"
/* Keep track of forward references to immediate-escalating functions in
case they become consteval. This vector contains ADDR_EXPRs and
diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc
index 7665b94..ee1c0ba 100644
--- a/gcc/cp/cp-objcp-common.cc
+++ b/gcc/cp/cp-objcp-common.cc
@@ -659,6 +659,7 @@ cp_common_init_ts (void)
MARK_TS_EXP (IF_STMT);
MARK_TS_EXP (OMP_DEPOBJ);
MARK_TS_EXP (RANGE_FOR_STMT);
+ MARK_TS_EXP (TEMPLATE_FOR_STMT);
MARK_TS_EXP (TRY_BLOCK);
MARK_TS_EXP (USING_STMT);
diff --git a/gcc/cp/cp-trait.def b/gcc/cp/cp-trait.def
index 9fedfd7..5e4493a 100644
--- a/gcc/cp/cp-trait.def
+++ b/gcc/cp/cp-trait.def
@@ -117,6 +117,7 @@ DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_cvref", 1)
DEFTRAIT_TYPE (REMOVE_EXTENT, "__remove_extent", 1)
DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
+DEFTRAIT_EXPR (STRUCTURED_BINDING_SIZE, "__builtin_structured_binding_size", 1)
DEFTRAIT_EXPR (TYPE_ORDER, "__builtin_type_order", 2)
DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index bb5aaf9..b1e3697 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -299,6 +299,11 @@ DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4)
templates. */
DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6)
+/* Used to represent an expansion-statement. The operands are
+ TEMPLATE_FOR_DECL, TEMPLATE_FOR_EXPR, TEMPLATE_FOR_BODY,
+ TEMPLATE_FOR_SCOPE, and TEMPLATE_FOR_INIT_STMT, respectively. */
+DEFTREECODE (TEMPLATE_FOR_STMT, "template_for_stmt", tcc_statement, 5)
+
/* Used to represent an expression statement. Use `EXPR_STMT_EXPR' to
obtain the expression. */
DEFTREECODE (EXPR_STMT, "expr_stmt", tcc_expression, 1)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0ac3ecb..8520ca0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -25,7 +25,6 @@ along with GCC; see the file COPYING3. If not see
#include "hard-reg-set.h"
#include "function.h"
#include "tristate.h"
-#include "contracts.h"
/* In order for the format checking to accept the C++ front end
diagnostic framework extensions, you must include this file before
@@ -453,6 +452,8 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
RETURN_EXPR_LOCAL_ADDR_P (in RETURN_EXPR)
PACK_INDEX_PARENTHESIZED_P (in PACK_INDEX_*)
MUST_NOT_THROW_NOEXCEPT_P (in MUST_NOT_THROW_EXPR)
+ CONSTEVAL_BLOCK_P (in STATIC_ASSERT)
+ LAMBDA_EXPR_CONSTEVAL_BLOCK_P (in LAMBDA_EXPR)
1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
@@ -474,6 +475,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR)
STATIC_INIT_DECOMP_BASE_P (in the TREE_LIST for {static,tls}_aggregates)
MUST_NOT_THROW_THROW_P (in MUST_NOT_THROW_EXPR)
+ LAMBDA_EXPR_CONST_QUAL_P (in LAMBDA_EXPR)
2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE)
ICS_THIS_FLAG (in _CONV)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@@ -1433,6 +1435,10 @@ struct GTY (()) tree_deferred_noexcept {
#define STATIC_ASSERT_SOURCE_LOCATION(NODE) \
(((struct tree_static_assert *)STATIC_ASSERT_CHECK (NODE))->location)
+/* True if this static assert represents a C++26 consteval block. */
+#define CONSTEVAL_BLOCK_P(NODE) \
+ TREE_LANG_FLAG_0 (STATIC_ASSERT_CHECK (NODE))
+
struct GTY (()) tree_static_assert {
struct tree_base base;
tree condition;
@@ -1547,6 +1553,17 @@ enum cp_lambda_default_capture_mode_type {
#define LAMBDA_EXPR_THIS_CAPTURE(NODE) \
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->this_capture)
+/* True iff this lambda was created for a consteval block. */
+#define LAMBDA_EXPR_CONSTEVAL_BLOCK_P(NODE) \
+ TREE_LANG_FLAG_0 (LAMBDA_EXPR_CHECK (NODE))
+
+/* True if we should add "const" when figuring out the type of an entity
+ in a lambda. This is false in the parameter-declaration-clause of
+ a lambda; after that, it will remain false if the mutable keyword is
+ present. */
+#define LAMBDA_EXPR_CONST_QUAL_P(NODE) \
+ TREE_LANG_FLAG_1 (LAMBDA_EXPR_CHECK (NODE))
+
/* True iff uses of a const variable capture were optimized away. */
#define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \
TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE))
@@ -1963,6 +1980,8 @@ struct GTY(()) saved_scope {
of consteval if statement. Also set while processing an immediate
invocation. */
BOOL_BITFIELD consteval_if_p : 1;
+ /* Nonzero if we are parsing the substatement of expansion-statement. */
+ BOOL_BITFIELD expansion_stmt : 1;
int unevaluated_operand;
int inhibit_evaluation_warnings;
@@ -2036,6 +2055,7 @@ extern GTY(()) struct saved_scope *scope_chain;
#define in_discarded_stmt scope_chain->discarded_stmt
#define in_consteval_if_p scope_chain->consteval_if_p
+#define in_expansion_stmt scope_chain->expansion_stmt
#define current_ref_temp_count scope_chain->ref_temp_count
@@ -2320,7 +2340,8 @@ enum languages { lang_c, lang_cplusplus };
/* Nonzero if NODE, a TYPE, has no name for linkage purposes. */
#define TYPE_UNNAMED_P(NODE) \
(TYPE_ANON_P (NODE) \
- && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE)))
+ && !IDENTIFIER_LAMBDA_P (TYPE_LINKAGE_IDENTIFIER (NODE)) \
+ && !enum_with_enumerator_for_linkage_p (NODE))
/* The _DECL for this _TYPE. */
#define TYPE_MAIN_DECL(NODE) (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE)))
@@ -5681,6 +5702,19 @@ decl_template_parm_check (const_tree t, const char *f, int l, const char *fn)
#define RANGE_FOR_IVDEP(NODE) TREE_LANG_FLAG_6 (RANGE_FOR_STMT_CHECK (NODE))
#define RANGE_FOR_NOVECTOR(NODE) TREE_LANG_FLAG_5 (RANGE_FOR_STMT_CHECK (NODE))
+/* TEMPLATE_FOR_STMT accessors. These give access to the declarator,
+ expression, body, and scope of the statement, respectively. */
+#define TEMPLATE_FOR_DECL(NODE) \
+ TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 0)
+#define TEMPLATE_FOR_EXPR(NODE) \
+ TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 1)
+#define TEMPLATE_FOR_BODY(NODE) \
+ TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 2)
+#define TEMPLATE_FOR_SCOPE(NODE) \
+ TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 3)
+#define TEMPLATE_FOR_INIT_STMT(NODE) \
+ TREE_OPERAND (TEMPLATE_FOR_STMT_CHECK (NODE), 4)
+
/* STMT_EXPR accessor. */
#define STMT_EXPR_STMT(NODE) TREE_OPERAND (STMT_EXPR_CHECK (NODE), 0)
@@ -6792,9 +6826,11 @@ struct GTY((chain_next ("%h.next"))) tinst_level {
/* The original node. TLDCL can be a DECL (for a function or static
data member), a TYPE (for a class), depending on what we were
- asked to instantiate, or a TREE_LIST with the template as PURPOSE
- and the template args as VALUE, if we are substituting for
- overload resolution. In all these cases, TARGS is NULL.
+ asked to instantiate, a TEMPLATE_FOR_STMT (for instantiation
+ of expansion stmt body outside of templates) or a TREE_LIST with
+ the template as PURPOSE and the template args as VALUE, if we are
+ substituting for overload resolution. In all these cases, TARGS
+ is NULL.
However, to avoid creating TREE_LIST objects for substitutions if
we can help, we store PURPOSE and VALUE in TLDCL and TARGS,
respectively. So TLDCL stands for TREE_LIST or DECL (the
@@ -7268,6 +7304,7 @@ extern void omp_declare_variant_finalize (tree, tree);
struct cp_decomp { tree decl; unsigned int count; };
extern void cp_finish_decl (tree, tree, bool, tree, int, cp_decomp * = nullptr);
extern tree lookup_decomp_type (tree);
+HOST_WIDE_INT cp_decomp_size (location_t, tree, tsubst_flags_t);
extern bool cp_finish_decomp (tree, cp_decomp *, bool = false);
extern int cp_complete_array_type (tree *, tree, bool);
extern int cp_complete_array_type_or_error (tree *, tree, bool, tsubst_flags_t);
@@ -7288,6 +7325,7 @@ extern tree xref_tag (tag_types, tree,
bool tpl_header_p = false);
extern void xref_basetypes (tree, tree);
extern tree start_enum (tree, tree, tree, tree, bool, bool *);
+extern bool enum_with_enumerator_for_linkage_p (tree);
extern void finish_enum_value_list (tree);
extern void finish_enum (tree);
extern tree build_enumerator (tree, tree, tree, tree, location_t);
@@ -7750,8 +7788,12 @@ extern tree clone_attrs (tree);
extern bool maybe_clone_body (tree);
/* In parser.cc */
+extern tree cp_build_range_for_decls (location_t, tree, tree *, bool);
extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool,
tree, bool);
+extern tree build_range_temp (tree);
+extern tree cp_perform_range_for_lookup (tree, tree *, tree *,
+ tsubst_flags_t = tf_warning_or_error);
extern void cp_convert_omp_range_for (tree &, tree &, tree &,
tree &, tree &, tree &, tree &, tree &,
bool);
@@ -7764,6 +7806,8 @@ extern location_t defparse_location (tree);
extern void maybe_show_extern_c_location (void);
extern bool literal_integer_zerop (const_tree);
extern tree attr_chainon (tree, tree);
+extern tree maybe_add_dummy_lambda_op (tree);
+extern void remove_dummy_lambda_op (tree, tree);
/* in pt.cc */
extern tree canonical_type_parameter (tree);
@@ -7968,6 +8012,7 @@ extern tree add_to_template_args (tree, tree);
extern tree add_outermost_template_args (tree, tree);
extern tree add_extra_args (tree, tree, tsubst_flags_t, tree);
extern tree build_extra_args (tree, tree, tsubst_flags_t);
+extern void finish_expansion_stmt (tree, tree, tsubst_flags_t, tree);
/* in rtti.cc */
/* A vector of all tinfo decls that haven't been emitted yet. */
@@ -8068,6 +8113,7 @@ public:
extern int stmts_are_full_exprs_p (void);
extern void init_cp_semantics (void);
extern tree do_poplevel (tree);
+extern tree do_pushlevel (scope_kind);
extern void break_maybe_infinite_loop (void);
extern void add_decl_expr (tree);
extern tree maybe_cleanup_point_expr_void (tree);
@@ -8094,7 +8140,7 @@ extern void find_range_for_decls (tree[3]);
extern void finish_for_stmt (tree);
extern tree begin_range_for_stmt (tree, tree);
extern void finish_range_for_decl (tree, tree, tree);
-extern void finish_range_for_stmt (tree);
+extern tree begin_template_for_scope (tree *);
extern tree finish_break_stmt (void);
extern tree finish_continue_stmt (void);
extern tree begin_switch_stmt (void);
@@ -8243,10 +8289,11 @@ extern bool cxx_omp_create_clause_info (tree, tree, bool, bool,
bool, bool);
extern tree baselink_for_fns (tree);
extern void finish_static_assert (tree, tree, location_t,
- bool, bool);
+ bool, bool, bool = false);
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_structured_binding_size (location_t, tree, tsubst_flags_t);
extern tree finish_trait_expr (location_t, enum cp_trait_kind, tree, tree);
extern tree finish_trait_type (enum cp_trait_kind, tree, tree, tsubst_flags_t);
extern tree build_lambda_expr (void);
@@ -8268,7 +8315,7 @@ extern void register_capture_members (tree);
extern tree lambda_expr_this_capture (tree, int);
extern void maybe_generic_this_capture (tree, tree);
extern tree maybe_resolve_dummy (tree, bool);
-extern tree current_nonlambda_function (void);
+extern tree current_nonlambda_function (bool = false);
extern tree nonlambda_method_basetype (void);
extern tree current_nonlambda_scope (bool = false);
extern tree current_lambda_expr (void);
@@ -8291,6 +8338,7 @@ extern void record_lambda_scope (tree lambda);
extern void record_lambda_scope_discriminator (tree lambda);
extern void record_lambda_scope_sig_discriminator (tree lambda, tree fn);
extern tree start_lambda_function (tree fn, tree lambda_expr);
+extern void push_capture_proxies (tree, bool = false);
extern void finish_lambda_function (tree body);
extern bool regenerated_lambda_fn_p (tree);
extern tree lambda_regenerating_args (tree);
@@ -9061,50 +9109,6 @@ extern tree coro_get_ramp_function (tree);
extern tree co_await_get_resume_call (tree await_expr);
-
-/* contracts.cc */
-extern tree make_postcondition_variable (cp_expr);
-extern tree make_postcondition_variable (cp_expr, tree);
-extern tree grok_contract (tree, tree, tree, cp_expr, location_t);
-extern tree finish_contract_condition (cp_expr);
-
-/* Return the first contract in ATTRS, or NULL_TREE if there are none. */
-
-inline tree
-find_contract (tree attrs)
-{
- while (attrs && !cxx_contract_attribute_p (attrs))
- attrs = TREE_CHAIN (attrs);
- return attrs;
-}
-
-inline void
-set_decl_contracts (tree decl, tree contract_attrs)
-{
- remove_contract_attributes (decl);
- DECL_ATTRIBUTES (decl) = chainon (DECL_ATTRIBUTES (decl), contract_attrs);
-}
-
-/* Returns the computed semantic of the node. */
-
-inline contract_semantic
-get_contract_semantic (const_tree t)
-{
- return (contract_semantic) (TREE_LANG_FLAG_3 (CONTRACT_CHECK (t))
- | (TREE_LANG_FLAG_2 (t) << 1)
- | (TREE_LANG_FLAG_0 ((t)) << 2));
-}
-
-/* Sets the computed semantic of the node. */
-
-inline void
-set_contract_semantic (tree t, contract_semantic semantic)
-{
- TREE_LANG_FLAG_3 (CONTRACT_CHECK (t)) = semantic & 0x01;
- TREE_LANG_FLAG_2 (t) = (semantic & 0x02) >> 1;
- TREE_LANG_FLAG_0 (t) = (semantic & 0x04) >> 2;
-}
-
/* Inline bodies. */
inline tree
diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index 5f24015..4916bf6 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -2137,6 +2137,29 @@ cxx_pretty_printer::statement (tree t)
pp_needs_newline (this) = true;
break;
+ case TEMPLATE_FOR_STMT:
+ pp_cxx_ws_string (this, "template for");
+ pp_space (this);
+ pp_cxx_left_paren (this);
+ if (TEMPLATE_FOR_INIT_STMT (t))
+ {
+ statement (TEMPLATE_FOR_INIT_STMT (t));
+ pp_needs_newline (this) = false;
+ pp_cxx_whitespace (this);
+ }
+ statement (TEMPLATE_FOR_DECL (t));
+ pp_space (this);
+ pp_needs_newline (this) = false;
+ pp_colon (this);
+ pp_space (this);
+ statement (TEMPLATE_FOR_EXPR (t));
+ pp_cxx_right_paren (this);
+ pp_newline_and_indent (this, 3);
+ statement (TEMPLATE_FOR_BODY (t));
+ pp_indentation (this) -= 3;
+ pp_needs_newline (this) = true;
+ break;
+
/* expression-statement:
expression(opt) ; */
case EXPR_STMT:
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index cb3ebff..f088d09 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see
#include "opts.h"
#include "langhooks-def.h" /* For lhd_simulate_record_decl */
#include "coroutines.h"
+#include "contracts.h"
#include "gcc-urlifier.h"
#include "diagnostic-highlight-colors.h"
#include "pretty-print-markup.h"
@@ -572,9 +573,9 @@ poplevel_named_label_1 (named_label_entry **slot, cp_binding_level *bl)
ent->in_stmt_expr = true;
break;
case sk_block:
- if (level_for_constexpr_if (bl->level_chain))
+ if (level_for_constexpr_if (obl))
ent->in_constexpr_if = true;
- else if (level_for_consteval_if (bl->level_chain))
+ else if (level_for_consteval_if (obl))
ent->in_consteval_if = true;
break;
default:
@@ -4336,7 +4337,19 @@ finish_case_label (location_t loc, tree low_value, tree high_value)
tree label;
/* For templates, just add the case label; we'll do semantic
- analysis at instantiation-time. */
+ analysis at instantiation-time. But diagnose case labels
+ in expansion statements with switch outside of it here. */
+ if (in_expansion_stmt)
+ for (cp_binding_level *b = current_binding_level;
+ b != switch_stack->level; b = b->level_chain)
+ if (b->kind == sk_template_for && b->this_entity)
+ {
+ auto_diagnostic_group d;
+ error ("jump to case label");
+ inform (EXPR_LOCATION (b->this_entity),
+ " enters %<template for%> statement");
+ return error_mark_node;
+ }
label = build_decl (loc, LABEL_DECL, NULL_TREE, void_type_node);
return add_stmt (build_case_label (low_value, high_value, label));
}
@@ -8595,6 +8608,13 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
variant = cp_get_callee_fndecl_nofold (STRIP_REFERENCE_REF (variant));
input_location = save_loc;
+ if (variant == decl)
+ {
+ error_at (varid_loc, "variant %qD is the same as base function",
+ variant);
+ return true;
+ }
+
if (variant)
{
bool fail;
@@ -9633,13 +9653,17 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
error has been diagnosed. */
static tree
-find_decomp_class_base (location_t loc, tree type, tree ret)
+find_decomp_class_base (location_t loc, tree type, tree ret,
+ tsubst_flags_t complain)
{
if (LAMBDA_TYPE_P (type))
{
- auto_diagnostic_group d;
- error_at (loc, "cannot decompose lambda closure type %qT", type);
- inform (location_of (type), "lambda declared here");
+ if (complain & tf_error)
+ {
+ auto_diagnostic_group d;
+ error_at (loc, "cannot decompose lambda closure type %qT", type);
+ inform (location_of (type), "lambda declared here");
+ }
return error_mark_node;
}
@@ -9653,6 +9677,8 @@ find_decomp_class_base (location_t loc, tree type, tree ret)
return type;
else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
+ if ((complain & tf_error) == 0)
+ return error_mark_node;
auto_diagnostic_group d;
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
error_at (loc, "cannot decompose class type %qT because it has an "
@@ -9665,6 +9691,8 @@ find_decomp_class_base (location_t loc, tree type, tree ret)
}
else if (!accessible_p (type, field, true))
{
+ if ((complain & tf_error) == 0)
+ return error_mark_node;
auto_diagnostic_group d;
error_at (loc, "cannot decompose inaccessible member %qD of %qT",
field, type);
@@ -9686,28 +9714,32 @@ find_decomp_class_base (location_t loc, tree type, tree ret)
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
{
auto_diagnostic_group d;
- tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret);
+ tree t = find_decomp_class_base (loc, TREE_TYPE (base_binfo), ret,
+ complain);
if (t == error_mark_node)
{
- inform (location_of (type), "in base class of %qT", type);
+ if (complain & tf_error)
+ inform (location_of (type), "in base class of %qT", type);
return error_mark_node;
}
if (t != NULL_TREE && t != ret)
{
if (ret == type)
{
- error_at (loc, "cannot decompose class type %qT: both it and "
- "its base class %qT have non-static data members",
- type, t);
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose class type %qT: both it and "
+ "its base class %qT have non-static data "
+ "members", type, t);
return error_mark_node;
}
else if (orig_ret != NULL_TREE)
return t;
else if (ret != NULL_TREE)
{
- error_at (loc, "cannot decompose class type %qT: its base "
- "classes %qT and %qT have non-static data "
- "members", type, ret, t);
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose class type %qT: its base "
+ "classes %qT and %qT have non-static data "
+ "members", type, ret, t);
return error_mark_node;
}
else
@@ -9738,7 +9770,7 @@ get_tuple_size (tree type)
if (val == error_mark_node)
return NULL_TREE;
if (VAR_P (val) || TREE_CODE (val) == CONST_DECL)
- val = maybe_constant_value (val);
+ val = maybe_constant_value (val, NULL_TREE, mce_true);
if (TREE_CODE (val) == INTEGER_CST)
return val;
else
@@ -9748,7 +9780,7 @@ get_tuple_size (tree type)
/* Return std::tuple_element<I,TYPE>::type. */
static tree
-get_tuple_element_type (tree type, unsigned i)
+get_tuple_element_type (tree type, unsigned HOST_WIDE_INT i)
{
tree args = make_tree_vec (2);
TREE_VEC_ELT (args, 0) = build_int_cst (integer_type_node, i);
@@ -9764,7 +9796,7 @@ get_tuple_element_type (tree type, unsigned i)
/* Return e.get<i>() or get<i>(e). */
static tree
-get_tuple_decomp_init (tree decl, unsigned i)
+get_tuple_decomp_init (tree decl, unsigned HOST_WIDE_INT i)
{
tree targs = make_tree_vec (1);
TREE_VEC_ELT (targs, 0) = build_int_cst (integer_type_node, i);
@@ -9870,6 +9902,134 @@ cp_maybe_mangle_decomp (tree decl, cp_decomp *decomp)
}
}
+/* Append #i to DECL_NAME (decl) or for name independent decls
+ clear DECL_NAME (decl). */
+
+static void
+set_sb_pack_name (tree decl, unsigned HOST_WIDE_INT i)
+{
+ if (name_independent_decl_p (decl))
+ /* Only "_" names are treated as name independent, "_#0" etc. is not and
+ because we pushdecl the individual decl elements of structured binding
+ pack, we could get redeclaration errors if there are 2 or more name
+ independent structured binding packs in the same scope. */
+ DECL_NAME (decl) = NULL_TREE;
+ else
+ {
+ tree name = DECL_NAME (decl);
+ size_t len = IDENTIFIER_LENGTH (name) + 22;
+ char *n = XALLOCAVEC (char, len);
+ snprintf (n, len, "%s#" HOST_WIDE_INT_PRINT_UNSIGNED,
+ IDENTIFIER_POINTER (name), i);
+ DECL_NAME (decl) = get_identifier (n);
+ }
+}
+
+/* Return structured binding size of TYPE or -1 if erroneous. */
+
+HOST_WIDE_INT
+cp_decomp_size (location_t loc, tree type, tsubst_flags_t complain)
+{
+ if (TYPE_REF_P (type))
+ {
+ type = complete_type (TREE_TYPE (type));
+ if (type == error_mark_node)
+ return -1;
+ if (!COMPLETE_TYPE_P (type))
+ {
+ if (complain & tf_error)
+ error_at (loc, "structured binding refers to incomplete type %qT",
+ type);
+ return -1;
+ }
+ }
+
+ unsigned HOST_WIDE_INT eltscnt = 0;
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ if (TYPE_DOMAIN (type) == NULL_TREE)
+ {
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose array of unknown bound %qT",
+ type);
+ return -1;
+ }
+ tree nelts = array_type_nelts_top (type);
+ if (nelts == error_mark_node)
+ return -1;
+ if (!tree_fits_shwi_p (nelts))
+ {
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose variable length array %qT", type);
+ return -1;
+ }
+ return tree_to_shwi (nelts);
+ }
+ /* 2 GNU extensions. */
+ else if (TREE_CODE (type) == COMPLEX_TYPE)
+ return 2;
+ else if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ if (!TYPE_VECTOR_SUBPARTS (type).is_constant (&eltscnt))
+ {
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose variable length vector %qT", type);
+ return -1;
+ }
+ return eltscnt;
+ }
+ else if (tree tsize = get_tuple_size (type))
+ {
+ if (tsize == error_mark_node
+ || !tree_fits_shwi_p (tsize)
+ || tree_int_cst_sgn (tsize) < 0)
+ {
+ if (complain & tf_error)
+ error_at (loc, "%<std::tuple_size<%T>::value%> is not an integral "
+ "constant expression", type);
+ return -1;
+ }
+ return tree_to_shwi (tsize);
+ }
+ else if (TREE_CODE (type) == UNION_TYPE)
+ {
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose union type %qT", type);
+ return -1;
+ }
+ else if (!CLASS_TYPE_P (type))
+ {
+ if (complain & tf_error)
+ error_at (loc, "cannot decompose non-array non-class type %qT", type);
+ return -1;
+ }
+ else if (processing_template_decl && complete_type (type) == error_mark_node)
+ return -1;
+ else if (!COMPLETE_TYPE_P (type))
+ {
+ if (complain & tf_error)
+ error_at (loc, "structured binding refers to incomplete class type "
+ "%qT", type);
+ return -1;
+ }
+ else
+ {
+ tree btype = find_decomp_class_base (loc, type, NULL_TREE, complain);
+ if (btype == error_mark_node)
+ return -1;
+ else if (btype == NULL_TREE)
+ return 0;
+ for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field))
+ if (TREE_CODE (field) != FIELD_DECL
+ || DECL_ARTIFICIAL (field)
+ || DECL_UNNAMED_BIT_FIELD (field))
+ continue;
+ else
+ eltscnt++;
+ return eltscnt;
+ }
+}
+
/* Finish a decomposition declaration. DECL is the underlying declaration
"e", FIRST is the head of a chain of decls for the individual identifiers
chained through DECL_CHAIN in reverse order and COUNT is the number of
@@ -9926,10 +10086,13 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
auto_vec<tree, 16> v;
v.safe_grow (count, true);
tree d = first;
+ int pack = -1;
for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d))
{
v[count - i - 1] = d;
fit_decomposition_lang_decl (d, decl);
+ if (DECL_PACK_P (d))
+ pack = count - i - 1;
}
tree type = TREE_TYPE (decl);
@@ -9951,6 +10114,14 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
tree eltype = NULL_TREE;
unsigned HOST_WIDE_INT eltscnt = 0;
+ /* Structured binding packs when initializer is non-dependent should
+ have their DECL_VALUE_EXPR set to a TREE_VEC. First two elements
+ of that TREE_VEC are the base and index, what is normally represented
+ as DECL_VALUE_EXPR ARRAY_REF <base, index> where index is the index
+ of the pack first element. The remaining elements of the TREE_VEC
+ are VAR_DECLs for the pack elements. */
+ tree packv = NULL_TREE;
+
if (TREE_CODE (type) == ARRAY_TYPE)
{
tree nelts;
@@ -9969,7 +10140,7 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
goto error_out;
}
eltscnt = tree_to_uhwi (nelts);
- if (count != eltscnt)
+ if (pack != -1 ? count - 1 > eltscnt : count != eltscnt)
{
cnt_mismatch:
auto_diagnostic_group d;
@@ -9990,12 +10161,37 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
eltype = TREE_TYPE (type);
for (unsigned int i = 0; i < count; i++)
{
+ if ((unsigned) pack == i)
+ {
+ packv = make_tree_vec (eltscnt - count + 3);
+ for (unsigned HOST_WIDE_INT j = 0; j < eltscnt - count + 1; ++j)
+ {
+ tree t;
+ TREE_VEC_ELT (packv, j + 2) = t = copy_node (v[pack]);
+ set_sb_pack_name (t, j);
+ maybe_push_decl (t);
+ TREE_TYPE (t) = eltype;
+ layout_decl (t, 0);
+ if (!processing_template_decl)
+ {
+ tree a = unshare_expr (dexp);
+ a = build4 (ARRAY_REF, eltype, a, size_int (j + pack),
+ NULL_TREE, NULL_TREE);
+ SET_DECL_VALUE_EXPR (t, a);
+ DECL_HAS_VALUE_EXPR_P (t) = 1;
+ }
+ }
+ continue;
+ }
TREE_TYPE (v[i]) = eltype;
layout_decl (v[i], 0);
if (processing_template_decl)
continue;
tree t = unshare_expr (dexp);
- t = build4 (ARRAY_REF, eltype, t, size_int (i), NULL_TREE, NULL_TREE);
+ unsigned HOST_WIDE_INT j = i;
+ if (pack != -1 && (unsigned) pack < i)
+ j = i + eltscnt - count;
+ t = build4 (ARRAY_REF, eltype, t, size_int (j), NULL_TREE, NULL_TREE);
SET_DECL_VALUE_EXPR (v[i], t);
DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
}
@@ -10004,17 +10200,41 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
else if (TREE_CODE (type) == COMPLEX_TYPE)
{
eltscnt = 2;
- if (count != eltscnt)
+ if (pack != -1 ? count - 1 > eltscnt : count != eltscnt)
goto cnt_mismatch;
eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
for (unsigned int i = 0; i < count; i++)
{
+ if ((unsigned) pack == i)
+ {
+ packv = make_tree_vec (eltscnt - count + 3);
+ for (unsigned HOST_WIDE_INT j = 0; j < eltscnt - count + 1; ++j)
+ {
+ tree t;
+ TREE_VEC_ELT (packv, j + 2) = t = copy_node (v[pack]);
+ set_sb_pack_name (t, j);
+ maybe_push_decl (t);
+ TREE_TYPE (t) = eltype;
+ layout_decl (t, 0);
+ if (!processing_template_decl)
+ {
+ tree a = build1 (pack + j ? IMAGPART_EXPR : REALPART_EXPR, eltype,
+ unshare_expr (dexp));
+ SET_DECL_VALUE_EXPR (t, a);
+ DECL_HAS_VALUE_EXPR_P (t) = 1;
+ }
+ }
+ continue;
+ }
TREE_TYPE (v[i]) = eltype;
layout_decl (v[i], 0);
if (processing_template_decl)
continue;
tree t = unshare_expr (dexp);
- t = build1 (i ? IMAGPART_EXPR : REALPART_EXPR, eltype, t);
+ unsigned HOST_WIDE_INT j = i;
+ if (pack != -1 && (unsigned) pack < i)
+ j = i + eltscnt - count;
+ t = build1 (j ? IMAGPART_EXPR : REALPART_EXPR, eltype, t);
SET_DECL_VALUE_EXPR (v[i], t);
DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
}
@@ -10026,19 +10246,47 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
error_at (loc, "cannot decompose variable length vector %qT", type);
goto error_out;
}
- if (count != eltscnt)
+ if (pack != -1 ? count - 1 > eltscnt : count != eltscnt)
goto cnt_mismatch;
eltype = cp_build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
for (unsigned int i = 0; i < count; i++)
{
+ if ((unsigned) pack == i)
+ {
+ packv = make_tree_vec (eltscnt - count + 3);
+ for (unsigned HOST_WIDE_INT j = 0; j < eltscnt - count + 1; ++j)
+ {
+ tree t;
+ TREE_VEC_ELT (packv, j + 2) = t = copy_node (v[pack]);
+ set_sb_pack_name (t, j);
+ maybe_push_decl (t);
+ TREE_TYPE (t) = eltype;
+ layout_decl (t, 0);
+ if (!processing_template_decl)
+ {
+ tree a = unshare_expr (dexp);
+ location_t loc = DECL_SOURCE_LOCATION (t);
+ tree s = size_int (j + pack);
+ convert_vector_to_array_for_subscript (loc, &a, s);
+ a = build4 (ARRAY_REF, eltype, a, s,
+ NULL_TREE, NULL_TREE);
+ SET_DECL_VALUE_EXPR (t, a);
+ DECL_HAS_VALUE_EXPR_P (t) = 1;
+ }
+ }
+ continue;
+ }
TREE_TYPE (v[i]) = eltype;
layout_decl (v[i], 0);
if (processing_template_decl)
continue;
tree t = unshare_expr (dexp);
+ unsigned HOST_WIDE_INT j = i;
+ if (pack != -1 && (unsigned) pack < i)
+ j = i + eltscnt - count;
convert_vector_to_array_for_subscript (DECL_SOURCE_LOCATION (v[i]),
- &t, size_int (i));
- t = build4 (ARRAY_REF, eltype, t, size_int (i), NULL_TREE, NULL_TREE);
+ &t, size_int (j));
+ t = build4 (ARRAY_REF, eltype, t, size_int (j), NULL_TREE, NULL_TREE);
SET_DECL_VALUE_EXPR (v[i], t);
DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
}
@@ -10062,11 +10310,11 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
goto error_out;
}
eltscnt = tree_to_uhwi (tsize);
- if (count != eltscnt)
+ if (pack != -1 ? count - 1 > eltscnt : count != eltscnt)
goto cnt_mismatch;
- if (test_p)
+ if (test_p && eltscnt)
return true;
- if (!processing_template_decl && DECL_DECOMP_BASE (decl))
+ if (!processing_template_decl && DECL_DECOMP_BASE (decl) && eltscnt)
{
/* For structured bindings used in conditions we need to evaluate
the conversion of decl (aka e in the standard) to bool or
@@ -10096,16 +10344,70 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
location_t sloc = input_location;
location_t dloc = DECL_SOURCE_LOCATION (v[i]);
+ if ((unsigned) pack == i)
+ {
+ packv = make_tree_vec (eltscnt - count + 3);
+ for (unsigned HOST_WIDE_INT j = 0; j < eltscnt - count + 1; ++j)
+ {
+ tree t;
+ TREE_VEC_ELT (packv, j + 2) = t = copy_node (v[pack]);
+ set_sb_pack_name (t, j);
+ input_location = dloc;
+ tree init = get_tuple_decomp_init (decl, j + pack);
+ tree eltype = (init == error_mark_node ? error_mark_node
+ : get_tuple_element_type (type, j + pack));
+ input_location = sloc;
+
+ if (VOID_TYPE_P (eltype))
+ {
+ error ("%<std::tuple_element<%wu, %T>::type%> is "
+ "%<void%>", j + pack, type);
+ eltype = error_mark_node;
+ }
+ if (init == error_mark_node || eltype == error_mark_node)
+ {
+ inform (dloc, "in initialization of structured binding "
+ "pack %qD", v[pack]);
+ goto error_out;
+ }
+ maybe_push_decl (t);
+ /* Save the decltype away before reference collapse. */
+ hash_map_safe_put<hm_ggc> (decomp_type_table, t, eltype);
+ eltype = cp_build_reference_type (eltype, !lvalue_p (init));
+ TREE_TYPE (t) = eltype;
+ layout_decl (t, 0);
+ DECL_HAS_VALUE_EXPR_P (t) = 0;
+ if (!processing_template_decl)
+ {
+ copy_linkage (t, decl);
+ tree name = DECL_NAME (t);
+ if (TREE_STATIC (decl))
+ DECL_NAME (t) = DECL_NAME (v[pack]);
+ cp_finish_decl (t, init, /*constexpr*/false,
+ /*asm*/NULL_TREE, LOOKUP_NORMAL);
+ if (TREE_STATIC (decl))
+ {
+ DECL_ASSEMBLER_NAME (t);
+ DECL_NAME (t) = name;
+ }
+ }
+ }
+ continue;
+ }
+
+ unsigned HOST_WIDE_INT j = i;
+ if (pack != -1 && (unsigned) pack < i)
+ j = i + eltscnt - count;
input_location = dloc;
- tree init = get_tuple_decomp_init (decl, i);
+ tree init = get_tuple_decomp_init (decl, j);
tree eltype = (init == error_mark_node ? error_mark_node
- : get_tuple_element_type (type, i));
+ : get_tuple_element_type (type, j));
input_location = sloc;
if (VOID_TYPE_P (eltype))
{
- error ("%<std::tuple_element<%u, %T>::type%> is %<void%>",
- i, type);
+ error ("%<std::tuple_element<%wu, %T>::type%> is %<void%>",
+ j, type);
eltype = error_mark_node;
}
if (init == error_mark_node || eltype == error_mark_node)
@@ -10154,11 +10456,18 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
type);
else
{
- tree btype = find_decomp_class_base (loc, type, NULL_TREE);
+ tree btype = find_decomp_class_base (loc, type, NULL_TREE,
+ tf_warning_or_error);
if (btype == error_mark_node)
goto error_out;
else if (btype == NULL_TREE)
{
+ if (pack == 0 && count == 1)
+ {
+ eltscnt = 0;
+ packv = make_tree_vec (2);
+ goto done;
+ }
error_at (loc, "cannot decompose class type %qT without non-static "
"data members", type);
goto error_out;
@@ -10170,7 +10479,7 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
continue;
else
eltscnt++;
- if (count != eltscnt)
+ if (pack != -1 ? count - 1 > eltscnt : count != eltscnt)
goto cnt_mismatch;
tree t = dexp;
if (type != btype)
@@ -10179,6 +10488,7 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
/*nonnull*/false, tf_warning_or_error);
type = btype;
}
+ unsigned HOST_WIDE_INT j = 0;
unsigned int i = 0;
for (tree field = TYPE_FIELDS (btype); field; field = TREE_CHAIN (field))
if (TREE_CODE (field) != FIELD_DECL
@@ -10191,6 +10501,32 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
NULL_TREE);
if (REFERENCE_REF_P (tt))
tt = TREE_OPERAND (tt, 0);
+ if (pack != -1 && j >= (unsigned) pack)
+ {
+ if (j == (unsigned) pack)
+ {
+ packv = make_tree_vec (eltscnt - count + 3);
+ i++;
+ }
+ if (j < (unsigned) pack + eltscnt - (count - 1))
+ {
+ tree t;
+ TREE_VEC_ELT (packv, j + 3 - i) = t = copy_node (v[pack]);
+ set_sb_pack_name (t, j + 1 - i);
+ maybe_push_decl (t);
+ TREE_TYPE (t) = TREE_TYPE (tt);
+ layout_decl (t, 0);
+ if (!processing_template_decl)
+ {
+ SET_DECL_VALUE_EXPR (t, tt);
+ DECL_HAS_VALUE_EXPR_P (t) = 1;
+ }
+ else
+ DECL_HAS_VALUE_EXPR_P (t) = 0;
+ j++;
+ continue;
+ }
+ }
TREE_TYPE (v[i]) = TREE_TYPE (tt);
layout_decl (v[i], 0);
if (!processing_template_decl)
@@ -10199,7 +10535,26 @@ cp_finish_decomp (tree decl, cp_decomp *decomp, bool test_p)
DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
}
i++;
+ j++;
}
+ if (pack != -1 && j == (unsigned) pack)
+ {
+ gcc_checking_assert (eltscnt == count - 1);
+ packv = make_tree_vec (2);
+ }
+ }
+ done:
+ if (packv)
+ {
+ gcc_checking_assert (pack != -1);
+ TREE_VEC_ELT (packv, 0) = decl;
+ TREE_VEC_ELT (packv, 1) = size_int (pack);
+ SET_DECL_VALUE_EXPR (v[pack], packv);
+ DECL_HAS_VALUE_EXPR_P (v[pack]) = 1;
+ DECL_IGNORED_P (v[pack]) = 1;
+ if (!processing_template_decl)
+ for (unsigned int i = 0; i < TREE_VEC_LENGTH (packv) - 2U; ++i)
+ pushdecl (TREE_VEC_ELT (packv, 2 + i));
}
if (processing_template_decl)
{
@@ -12670,6 +13025,88 @@ mark_inline_variable (tree decl, location_t loc)
}
+/* Diagnose -Wnon-c-typedef-for-linkage pedwarn. TYPE is the unnamed class
+ with a typedef name for linkage purposes with freshly updated TYPE_NAME,
+ ORIG is the anonymous TYPE_NAME before that change. */
+
+static bool
+diagnose_non_c_class_typedef_for_linkage (tree type, tree orig)
+{
+ gcc_rich_location richloc (DECL_SOURCE_LOCATION (orig));
+ tree name = DECL_NAME (TYPE_NAME (type));
+ richloc.add_fixit_insert_before (IDENTIFIER_POINTER (name));
+ return pedwarn (&richloc, OPT_Wnon_c_typedef_for_linkage,
+ "anonymous non-C-compatible type given name for linkage "
+ "purposes by %<typedef%> declaration");
+}
+
+/* Diagnose -Wnon-c-typedef-for-linkage violations on T. TYPE and ORIG
+ like for diagnose_non_c_class_typedef_for_linkage, T is initially equal
+ to TYPE but during recursion can be set to nested classes. */
+
+static bool
+maybe_diagnose_non_c_class_typedef_for_linkage (tree type, tree orig, tree t)
+{
+ if (!BINFO_BASE_BINFOS (TYPE_BINFO (t))->is_empty ())
+ {
+ auto_diagnostic_group d;
+ if (diagnose_non_c_class_typedef_for_linkage (type, orig))
+ inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)),
+ "type is not C-compatible because it has a base class");
+ return true;
+ }
+ for (tree field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
+ switch (TREE_CODE (field))
+ {
+ case VAR_DECL:
+ /* static data members have been diagnosed already. */
+ continue;
+ case FIELD_DECL:
+ if (DECL_INITIAL (field))
+ {
+ auto_diagnostic_group d;
+ if (diagnose_non_c_class_typedef_for_linkage (type, orig))
+ inform (DECL_SOURCE_LOCATION (field),
+ "type is not C-compatible because %qD has default "
+ "member initializer", field);
+ return true;
+ }
+ continue;
+ case CONST_DECL:
+ continue;
+ case TYPE_DECL:
+ if (DECL_SELF_REFERENCE_P (field))
+ continue;
+ if (DECL_IMPLICIT_TYPEDEF_P (field))
+ {
+ if (TREE_CODE (TREE_TYPE (field)) == ENUMERAL_TYPE)
+ continue;
+ if (CLASS_TYPE_P (TREE_TYPE (field)))
+ {
+ tree tf = TREE_TYPE (field);
+ if (maybe_diagnose_non_c_class_typedef_for_linkage (type, orig,
+ tf))
+ return true;
+ continue;
+ }
+ }
+ /* FALLTHRU */
+ case FUNCTION_DECL:
+ case TEMPLATE_DECL:
+ {
+ auto_diagnostic_group d;
+ if (diagnose_non_c_class_typedef_for_linkage (type, orig))
+ inform (DECL_SOURCE_LOCATION (field),
+ "type is not C-compatible because it contains %qD "
+ "declaration", field);
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
/* Assign a typedef-given name to a class or enumeration type declared
as anonymous at first. This was split out of grokdeclarator
because it is also used in libcc1. */
@@ -12677,7 +13114,8 @@ mark_inline_variable (tree decl, location_t loc)
void
name_unnamed_type (tree type, tree decl)
{
- gcc_assert (TYPE_UNNAMED_P (type));
+ gcc_assert (TYPE_UNNAMED_P (type)
+ || enum_with_enumerator_for_linkage_p (type));
/* Replace the anonymous decl with the real decl. Be careful not to
rename other typedefs (such as the self-reference) of type. */
@@ -12695,12 +13133,16 @@ name_unnamed_type (tree type, tree decl)
/* Adjust linkage now that we aren't unnamed anymore. */
reset_type_linkage (type);
+ if (CLASS_TYPE_P (type) && warn_non_c_typedef_for_linkage)
+ maybe_diagnose_non_c_class_typedef_for_linkage (type, orig, type);
+
/* FIXME remangle member functions; member functions of a
type with external linkage have external linkage. */
/* Check that our job is done, and that it would fail if we
attempted to do it again. */
- gcc_assert (!TYPE_UNNAMED_P (type));
+ gcc_assert (!TYPE_UNNAMED_P (type)
+ && !enum_with_enumerator_for_linkage_p (type));
}
/* Check that decltype(auto) was well-formed: only plain decltype(auto)
@@ -14950,7 +15392,10 @@ grokdeclarator (const cp_declarator *declarator,
&& unqualified_id
&& TYPE_NAME (type)
&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
- && TYPE_UNNAMED_P (type)
+ && (TYPE_UNNAMED_P (type)
+ /* An enum may have previously used an enumerator for linkage
+ purposes, but we want the typedef name to take priority. */
+ || enum_with_enumerator_for_linkage_p (type))
&& declspecs->type_definition_p
&& attributes_naming_typedef_ok (*attrlist)
&& cp_type_quals (type) == TYPE_UNQUALIFIED)
@@ -17793,6 +18238,18 @@ start_enum (tree name, tree enumtype, tree underlying_type,
return enumtype;
}
+/* Returns true if TYPE is an enum that uses an enumerator name for
+ linkage purposes. */
+
+bool
+enum_with_enumerator_for_linkage_p (tree type)
+{
+ return (cxx_dialect >= cxx20
+ && UNSCOPED_ENUM_P (type)
+ && TYPE_ANON_P (type)
+ && TYPE_VALUES (type));
+}
+
/* After processing and defining all the values of an enumeration type,
install their decls in the enumeration type.
ENUMTYPE is the type object. */
@@ -18023,6 +18480,11 @@ finish_enum_value_list (tree enumtype)
fixup_type_variants (current_class_type);
}
+ /* P2115: An unnamed enum uses the name of its first enumerator for
+ linkage purposes; reset the type linkage if that is the case. */
+ if (enum_with_enumerator_for_linkage_p (enumtype))
+ reset_type_linkage (enumtype);
+
/* Finish debugging output for this type. */
rest_of_type_compilation (enumtype, namespace_bindings_p ());
@@ -18440,6 +18902,8 @@ build_clobber_this (clobber_kind kind)
}
tree exprstmt = build2 (MODIFY_EXPR, void_type_node, thisref, clobber);
+ if (kind == CLOBBER_OBJECT_BEGIN)
+ TREE_SET_CODE (exprstmt, INIT_EXPR);
if (vbases)
exprstmt = build_if_in_charge (exprstmt);
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 2bbc618..6499be1 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see
#include "omp-general.h"
#include "tree-inline.h"
#include "escaped_string.h"
+#include "contracts.h"
/* Id for dumping the raw trees. */
int raw_dump_id;
@@ -6229,6 +6230,7 @@ cp_warn_deprecated_use_scopes (tree scope)
bool
decl_dependent_p (tree decl)
{
+ tree orig_decl = decl;
if (DECL_FUNCTION_SCOPE_P (decl)
|| TREE_CODE (decl) == CONST_DECL
|| TREE_CODE (decl) == USING_DECL
@@ -6240,6 +6242,13 @@ decl_dependent_p (tree decl)
if (LAMBDA_FUNCTION_P (decl)
&& dependent_type_p (DECL_CONTEXT (decl)))
return true;
+ /* for-range-declaration of expansion statement as well as variable
+ declarations in the expansion statement body when the expansion statement
+ is not inside a template still need to be treated as dependent during
+ parsing. When the body is instantiated, in_expansion_stmt will be already
+ false. */
+ if (VAR_P (orig_decl) && in_expansion_stmt && decl == current_function_decl)
+ return true;
return false;
}
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index c427163..8ef9f9e 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -250,7 +250,7 @@ erroneous_templates_t *erroneous_templates;
issue an error if we later need to instantiate the template. */
static void
-cp_adjust_diagnostic_info (diagnostics::context *context,
+cp_adjust_diagnostic_info (const diagnostics::context &context,
diagnostics::diagnostic_info *diagnostic)
{
if (diagnostic->m_kind == diagnostics::kind::error)
@@ -258,7 +258,7 @@ cp_adjust_diagnostic_info (diagnostics::context *context,
{
diagnostic->m_option_id = OPT_Wtemplate_body;
- if (context->m_permissive)
+ if (context.m_permissive)
diagnostic->m_kind = diagnostics::kind::warning;
bool existed;
@@ -3953,14 +3953,20 @@ print_instantiation_full_context (diagnostics::text_sink &text_output)
= ((!text_output.show_nesting_p ())
|| text_output.show_locations_in_nesting_p ());
char *indent = text_output.build_indent_prefix (true);
+ bool expansion_stmt_p = TREE_CODE (p->tldcl) == TEMPLATE_FOR_STMT;
pp_verbatim (text_output.get_printer (),
- p->list_p ()
+ expansion_stmt_p
+ ? G_("%s%s%sIn instantiation of %<template for%> "
+ "iteration %E:\n")
+ : p->list_p ()
? G_("%s%s%sIn substitution of %qS:\n")
: G_("%s%s%sIn instantiation of %q#D:\n"),
indent,
show_file ? LOCATION_FILE (location) : "",
show_file ? ": " : "",
- p->get_node ());
+ expansion_stmt_p
+ ? TREE_VEC_ELT (p->targs, 0)
+ : p->get_node ());
free (indent);
location = p->locus;
p = p->next;
@@ -4069,7 +4075,14 @@ print_instantiation_partial_context_line (diagnostics::text_sink &text_output,
if (t != NULL)
{
- if (t->list_p ())
+ if (TREE_CODE (t->tldcl) == TEMPLATE_FOR_STMT)
+ pp_verbatim (pp,
+ recursive_p
+ ? G_("recursively required from %<template for%> "
+ "iteration %E\n")
+ : G_("required from %<template for%> iteration %E\n"),
+ TREE_VEC_ELT (t->targs, 0));
+ else if (t->list_p ())
pp_verbatim (pp,
recursive_p
? G_("recursively required by substitution of %qS\n")
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index 2c1ef4c..204769f 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -1218,13 +1218,15 @@ expr_noexcept_p (tree expr, tsubst_flags_t complain)
return true;
}
-/* Explain why EXPR is not noexcept. */
+/* If EXPR is not noexcept, explain why. */
-void explain_not_noexcept (tree expr)
+void
+explain_not_noexcept (tree expr)
{
tree fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0);
- gcc_assert (fn);
- if (DECL_P (fn))
+ if (!fn)
+ /* The call was noexcept, nothing to do. */;
+ else if (DECL_P (fn))
inform (DECL_SOURCE_LOCATION (fn), "%qD is not %<noexcept%>", fn);
else
inform (location_of (fn), "%qT is not %<noexcept%>", TREE_TYPE (fn));
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 09fb4f3..f19794c 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -3557,9 +3557,19 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
alloc_expr = maybe_wrap_new_for_constexpr (alloc_expr, type,
cookie_size);
+ bool std_placement = std_placement_new_fn_p (alloc_fn);
+
+ /* For std placement new, clobber the object if the constructor won't do it
+ in start_preparsed_function. This is most important for activating an
+ array in a union (c++/121068), but should also help the optimizers. */
+ const bool do_clobber
+ = (std_placement && !*init && flag_lifetime_dse > 1
+ && (!CLASS_TYPE_P (elt_type)
+ || type_has_non_user_provided_default_constructor (elt_type)));
+
/* In the simple case, we can stop now. */
pointer_type = build_pointer_type (type);
- if (!cookie_size && !is_initialized && !member_delete_p)
+ if (!cookie_size && !is_initialized && !member_delete_p && !do_clobber)
return build_nop (pointer_type, alloc_expr);
/* Store the result of the allocation call in a variable so that we can
@@ -3593,8 +3603,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
So check for a null exception spec on the op new we just called. */
nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn));
- check_new
- = flag_check_new || (nothrow && !std_placement_new_fn_p (alloc_fn));
+ check_new = flag_check_new || (nothrow && !std_placement);
if (cookie_size)
{
@@ -3649,6 +3658,29 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
/* Any further uses of alloc_node will want this type, too. */
alloc_node = fold_convert (non_const_pointer_type, alloc_node);
+ tree clobber_expr = NULL_TREE;
+ if (do_clobber)
+ {
+ tree clobber = build_clobber (elt_type, CLOBBER_OBJECT_BEGIN);
+ CONSTRUCTOR_IS_DIRECT_INIT (clobber) = true;
+ if (array_p)
+ {
+ /* Clobber each element rather than the array at once. */
+ tree maxindex = cp_build_binary_op (input_location,
+ MINUS_EXPR, outer_nelts,
+ integer_one_node,
+ complain);
+ clobber_expr = build_vec_init (data_addr, maxindex, clobber,
+ /*valinit*/false, /*from_arr*/0,
+ complain, nullptr);
+ }
+ else
+ {
+ tree targ = cp_build_fold_indirect_ref (data_addr);
+ clobber_expr = cp_build_init_expr (targ, clobber);
+ }
+ }
+
/* Now initialize the allocated object. Note that we preevaluate the
initialization expression, apart from the actual constructor call or
assignment--we do this because we want to delay the allocation as long
@@ -3877,6 +3909,8 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
if (init_expr)
rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), init_expr, rval);
+ if (clobber_expr)
+ rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), clobber_expr, rval);
if (cookie_expr)
rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval);
@@ -4717,6 +4751,9 @@ build_vec_init (tree base, tree maxindex, tree init,
the partially constructed array if an exception is thrown.
But don't do this if we're assigning. */
if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
+ /* And don't clean up from clobbers, the actual initialization will
+ follow as a separate build_vec_init. */
+ && !(init && TREE_CLOBBER_P (init))
&& from_array != 2)
{
tree e;
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index ecf55eb..711e3b7 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -409,10 +409,11 @@ lambda_proxy_type (tree ref)
/* MEMBER is a capture field in a lambda closure class. Now that we're
inside the operator(), build a placeholder var for future lookups and
- debugging. */
+ debugging. But if EARLY_P is true, we do not have the real operator()
+ yet and we have to proceed differently. */
-static tree
-build_capture_proxy (tree member, tree init)
+tree
+build_capture_proxy (tree member, tree init, bool early_p)
{
tree var, object, fn, closure, name, lam, type;
@@ -503,11 +504,19 @@ build_capture_proxy (tree member, tree init)
if (name == this_identifier)
{
+ if (early_p)
+ return var;
gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (lam) == member);
LAMBDA_EXPR_THIS_CAPTURE (lam) = var;
}
- if (fn == current_function_decl)
+ if (early_p)
+ {
+ gcc_checking_assert (current_binding_level->kind == sk_lambda);
+ /* insert_capture_proxy below wouldn't push into the lambda scope. */
+ pushdecl (var);
+ }
+ else if (fn == current_function_decl)
insert_capture_proxy (var);
else
vec_safe_push (LAMBDA_EXPR_PENDING_PROXIES (lam), var);
@@ -727,7 +736,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
= tree_cons (listmem, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
if (LAMBDA_EXPR_CLOSURE (lambda))
- return build_capture_proxy (member, initializer);
+ return build_capture_proxy (member, initializer, /*early_p=*/false);
/* For explicit captures we haven't started the function yet, so we wait
and build the proxy from cp_parser_lambda_body. */
LAMBDA_CAPTURE_EXPLICIT_P (LAMBDA_EXPR_CAPTURE_LIST (lambda)) = true;
@@ -980,10 +989,14 @@ resolvable_dummy_lambda (tree object)
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (object));
gcc_assert (!TYPE_PTR_P (type));
+ tree fn;
if (type != current_class_type
&& current_class_type
&& LAMBDA_TYPE_P (current_class_type)
- && lambda_function (current_class_type)
+ && (fn = lambda_function (current_class_type))
+ /* Even dummy lambdas have an operator() since P2036, but the
+ dummy operator() doesn't have this set. */
+ && DECL_LAMBDA_FUNCTION_P (fn)
&& DERIVED_FROM_P (type, nonlambda_method_basetype()))
return CLASSTYPE_LAMBDA_EXPR (current_class_type);
@@ -1038,13 +1051,19 @@ maybe_generic_this_capture (tree object, tree fns)
}
}
-/* Returns the innermost non-lambda function. */
+/* Returns the innermost non-lambda function. If ONLY_SKIP_CONSTEVAL_BLOCK_P,
+ we only skip lambda functions that represent consteval blocks. */
tree
-current_nonlambda_function (void)
+current_nonlambda_function (bool only_skip_consteval_block_p/*=false*/)
{
tree fn = current_function_decl;
- while (fn && LAMBDA_FUNCTION_P (fn))
+ tree lam;
+ while (fn && LAMBDA_FUNCTION_P (fn)
+ && (!only_skip_consteval_block_p
+ /* Only keep going if FN represents a consteval block. */
+ || ((lam = CLASSTYPE_LAMBDA_EXPR (CP_DECL_CONTEXT (fn)))
+ && LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lam))))
fn = decl_function_context (fn);
return fn;
}
@@ -1778,6 +1797,17 @@ record_lambda_scope_sig_discriminator (tree lambda, tree fn)
LAMBDA_EXPR_SCOPE_SIG_DISCRIMINATOR (lambda) = sig->count++;
}
+/* Push the proxies for any explicit captures in LAMBDA_EXPR.
+ If EARLY_P, we do not have the real operator() yet. */
+
+void
+push_capture_proxies (tree lambda_expr, bool early_p)
+{
+ for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;
+ cap = TREE_CHAIN (cap))
+ build_capture_proxy (TREE_PURPOSE (cap), TREE_VALUE (cap), early_p);
+}
+
tree
start_lambda_function (tree fco, tree lambda_expr)
{
@@ -1790,9 +1820,7 @@ start_lambda_function (tree fco, tree lambda_expr)
tree body = begin_function_body ();
/* Push the proxies for any explicit captures. */
- for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;
- cap = TREE_CHAIN (cap))
- build_capture_proxy (TREE_PURPOSE (cap), TREE_VALUE (cap));
+ push_capture_proxies (lambda_expr);
return body;
}
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 08a6348..da86989 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -172,7 +172,7 @@ init_operators (void)
/* This loop iterates backwards because we need to move the
assignment operators down to their correct slots. I.e. morally
equivalent to an overlapping memmove where dest > src. Slot
- zero is for error_mark, so hae no operator. */
+ zero is for error_mark, so has no operator. */
for (unsigned ix = OVL_OP_MAX; --ix;)
{
ovl_op_info_t *op_ptr = &ovl_op_info[false][ix];
@@ -368,6 +368,61 @@ cxx_init (void)
cxx_init_decl_processing ();
+ if (warn_keyword_macro)
+ {
+ for (unsigned int i = 0; i < num_c_common_reswords; ++i)
+ /* For C++ none of the keywords in [lex.key] starts with underscore,
+ don't register anything like that. Don't complain about
+ ObjC or Transactional Memory keywords. */
+ if (c_common_reswords[i].word[0] == '_')
+ continue;
+ else if (c_common_reswords[i].disable & (D_TRANSMEM | D_OBJC))
+ continue;
+ else
+ {
+ tree id = get_identifier (c_common_reswords[i].word);
+ if (IDENTIFIER_KEYWORD_P (id)
+ /* Don't register keywords with spaces. */
+ && IDENTIFIER_POINTER (id)[IDENTIFIER_LENGTH (id) - 1] != ' ')
+ cpp_warn (parse_in, IDENTIFIER_POINTER (id),
+ IDENTIFIER_LENGTH (id));
+ }
+ if (cxx_dialect >= cxx11)
+ {
+ cpp_warn (parse_in, "final");
+ cpp_warn (parse_in, "override");
+ cpp_warn (parse_in, "noreturn");
+ if (cxx_dialect < cxx26)
+ cpp_warn (parse_in, "carries_dependency");
+ }
+ if (cxx_dialect >= cxx14)
+ cpp_warn (parse_in, "deprecated");
+ if (cxx_dialect >= cxx17)
+ {
+ cpp_warn (parse_in, "fallthrough");
+ cpp_warn (parse_in, "maybe_unused");
+ cpp_warn (parse_in, "nodiscard");
+ }
+ if (cxx_dialect >= cxx20)
+ {
+ cpp_warn (parse_in, "likely");
+ cpp_warn (parse_in, "unlikely");
+ cpp_warn (parse_in, "no_unique_address");
+ }
+ if (flag_modules)
+ {
+ cpp_warn (parse_in, "import");
+ cpp_warn (parse_in, "module");
+ }
+ if (cxx_dialect >= cxx23)
+ cpp_warn (parse_in, "assume");
+ if (cxx_dialect >= cxx26)
+ {
+ cpp_warn (parse_in, "replaceable_if_eligible");
+ cpp_warn (parse_in, "trivially_relocatable_if_eligible");
+ }
+ }
+
if (c_common_init () == false)
{
input_location = saved_loc;
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 13d5ded..80be40d 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see
#include "stor-layout.h"
#include "flags.h"
#include "attribs.h"
+#include "contracts.h"
/* Debugging support. */
@@ -203,6 +204,7 @@ static void write_conversion_operator_name (const tree);
static void write_source_name (tree);
static void write_literal_operator_name (tree);
static void write_unnamed_type_name (const tree);
+static void write_unnamed_enum_name (const tree);
static void write_closure_type_name (const tree);
static int hwint_to_ascii (unsigned HOST_WIDE_INT, const unsigned int, char *,
const unsigned int);
@@ -1591,7 +1593,9 @@ write_unqualified_name (tree decl)
tree type = TREE_TYPE (decl);
if (TREE_CODE (decl) == TYPE_DECL
- && TYPE_UNNAMED_P (type))
+ && enum_with_enumerator_for_linkage_p (type))
+ write_unnamed_enum_name (type);
+ else if (TREE_CODE (decl) == TYPE_DECL && TYPE_UNNAMED_P (type))
write_unnamed_type_name (type);
else if (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (type))
write_closure_type_name (type);
@@ -1820,6 +1824,17 @@ write_unnamed_type_name (const tree type)
write_compact_number (discriminator);
}
+/* <unnamed-enum-name> ::= Ue <underlying type> <enumerator source-name> */
+
+static void
+write_unnamed_enum_name (const tree type)
+{
+ MANGLE_TRACE_TREE ("unnamed-enum-name", type);
+ write_string ("Ue");
+ write_type (ENUM_UNDERLYING_TYPE (type));
+ write_source_name (DECL_NAME (TREE_VALUE (TYPE_VALUES (type))));
+}
+
/* ABI issue #47: if a function template parameter is not "natural" for its
argument we must mangle the parameter. */
@@ -3745,11 +3760,59 @@ write_expression (tree expr)
|| !zero_init_expr_p (ce->value))
last_nonzero = i;
+ tree prev_field = NULL_TREE;
if (undigested || last_nonzero != UINT_MAX)
for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i)
{
if (i > last_nonzero)
break;
+ if (!undigested && !CONSTRUCTOR_NO_CLEARING (expr)
+ && (TREE_CODE (etype) == RECORD_TYPE
+ || TREE_CODE (etype) == ARRAY_TYPE))
+ {
+ /* Write out any implicit non-trailing zeros
+ (which we neglected to do before v21). */
+ if (TREE_CODE (etype) == RECORD_TYPE)
+ {
+ tree field;
+ if (i == 0)
+ field = first_field (etype);
+ else
+ field = DECL_CHAIN (prev_field);
+ for (;;)
+ {
+ field = next_subobject_field (field);
+ if (field == ce->index)
+ break;
+ if (abi_check (21))
+ write_expression (build_zero_cst
+ (TREE_TYPE (field)));
+ field = DECL_CHAIN (field);
+ }
+ }
+ else if (TREE_CODE (etype) == ARRAY_TYPE)
+ {
+ unsigned HOST_WIDE_INT j;
+ if (i == 0)
+ j = 0;
+ else
+ j = 1 + tree_to_uhwi (prev_field);
+ unsigned HOST_WIDE_INT k;
+ if (TREE_CODE (ce->index) == RANGE_EXPR)
+ k = tree_to_uhwi (TREE_OPERAND (ce->index, 0));
+ else
+ k = tree_to_uhwi (ce->index);
+ tree zero = NULL_TREE;
+ for (; j < k; ++j)
+ if (abi_check (21))
+ {
+ if (!zero)
+ zero = build_zero_cst (TREE_TYPE (etype));
+ write_expression (zero);
+ }
+ }
+ }
+
if (!undigested && TREE_CODE (etype) == UNION_TYPE)
{
/* Express the active member as a designator. */
@@ -3794,6 +3857,9 @@ write_expression (tree expr)
else
for (unsigned j = 0; j < reps; ++j)
write_expression (ce->value);
+ prev_field = ce->index;
+ if (prev_field && TREE_CODE (prev_field) == RANGE_EXPR)
+ prev_field = TREE_OPERAND (prev_field, 1);
}
}
else
diff --git a/gcc/cp/mapper-client.cc b/gcc/cp/mapper-client.cc
index 9477fee..ac414f0 100644
--- a/gcc/cp/mapper-client.cc
+++ b/gcc/cp/mapper-client.cc
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see
#define INCLUDE_VECTOR
#define INCLUDE_MAP
#include "system.h"
+#include "libiberty.h"
#include "line-map.h"
#include "rich-location.h"
@@ -51,37 +52,18 @@ static module_client *
spawn_mapper_program (char const **errmsg, std::string &name,
char const *full_program_name)
{
- /* Split writable at white-space. No space-containing args for
- you! */
- // At most every other char could be an argument
- char **argv = new char *[name.size () / 2 + 2];
- unsigned arg_no = 0;
- char *str = new char[name.size ()];
- memcpy (str, name.c_str () + 1, name.size ());
-
- for (auto ptr = str; ; ++ptr)
- {
- while (*ptr == ' ')
- ptr++;
- if (!*ptr)
- break;
-
- if (!arg_no)
- {
- /* @name means look in the compiler's install dir. */
- if (ptr[0] == '@')
- ptr++;
- else
- full_program_name = nullptr;
- }
-
- argv[arg_no++] = ptr;
- while (*ptr && *ptr != ' ')
- ptr++;
- if (!*ptr)
- break;
- *ptr = 0;
- }
+ // Split mapper argument into parameters.
+ char** original_argv = buildargv (name.c_str () + 1);
+ int arg_no = countargv (original_argv);
+ char **argv = new char *[arg_no + 1];
+ for (int i = 0; i < arg_no; i++)
+ argv[i] = original_argv[i];
+
+ /* @name means look in the compiler's install dir. */
+ if (arg_no && argv[0][0] == '@')
+ argv[0] = argv[0] + 1;
+ else
+ full_program_name = nullptr;
argv[arg_no] = nullptr;
auto *pex = pex_init (PEX_USE_PIPES, progname, NULL);
@@ -108,8 +90,8 @@ spawn_mapper_program (char const **errmsg, std::string &name,
int err;
*errmsg = pex_run (pex, flags, argv[0], argv, NULL, NULL, &err);
}
- delete[] str;
delete[] argv;
+ freeargv (original_argv);
int fd_from = -1, fd_to = -1;
if (!*errmsg)
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 62f8d80..ef8370f 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1851,6 +1851,9 @@ synthesize_method (tree fndecl)
finish_function_body (stmt);
finish_function (/*inline_p=*/false);
+ /* Remember that we were defined in this module. */
+ set_instantiating_module (fndecl);
+
if (!DECL_DELETED_FN (fndecl))
expand_or_defer_fn (fndecl);
@@ -1952,7 +1955,8 @@ build_trait_object (tree type, tsubst_flags_t complain)
}
/* [func.require] Build an expression of INVOKE(FN_TYPE, ARG_TYPES...). If the
- given is not invocable, returns error_mark_node. */
+ given is not invocable, returns error_mark_node, unless COMPLAIN includes
+ tf_error. */
tree
build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
@@ -2460,21 +2464,13 @@ bool
is_trivially_xible (enum tree_code code, tree to, tree from,
bool explain/*=false*/)
{
- /* In some cases, when producing errors is_xible_helper may not return
- error_mark_node, so check if it looks like we've already emitted any
- diagnostics to ensure we don't do so multiple times. */
- int errs = errorcount + sorrycount;
-
tree expr = is_xible_helper (code, to, from, explain);
if (expr == NULL_TREE || expr == error_mark_node)
return false;
tree nt = cp_walk_tree_without_duplicates (&expr, check_nontriv, NULL);
- if (explain && errs == (errorcount + sorrycount))
- {
- gcc_assert (nt);
- inform (location_of (nt), "%qE is non-trivial", nt);
- }
+ if (explain && nt)
+ inform (location_of (nt), "%qE is non-trivial", nt);
return !nt;
}
@@ -2487,9 +2483,6 @@ bool
is_nothrow_xible (enum tree_code code, tree to, tree from,
bool explain/*=false*/)
{
- /* As with is_trivially_xible. */
- int errs = errorcount + sorrycount;
-
++cp_noexcept_operand;
tree expr = is_xible_helper (code, to, from, explain);
--cp_noexcept_operand;
@@ -2497,11 +2490,8 @@ is_nothrow_xible (enum tree_code code, tree to, tree from,
return false;
bool is_noexcept = expr_noexcept_p (expr, tf_none);
- if (explain && errs == (errorcount + sorrycount))
- {
- gcc_assert (!is_noexcept);
- explain_not_noexcept (expr);
- }
+ if (explain && !is_noexcept)
+ explain_not_noexcept (expr);
return is_noexcept;
}
@@ -2601,12 +2591,10 @@ is_nothrow_convertible (tree from, tree to, bool explain/*=false*/)
tree expr = is_convertible_helper (from, to, explain);
if (expr == NULL_TREE || expr == error_mark_node)
return false;
+
bool is_noexcept = expr_noexcept_p (expr, tf_none);
- if (explain)
- {
- gcc_assert (!is_noexcept);
- explain_not_noexcept (expr);
- }
+ if (explain && !is_noexcept)
+ explain_not_noexcept (expr);
return is_noexcept;
}
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 2f6a8ab..0404eae6 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -232,6 +232,7 @@ Classes used:
#include "attribs.h"
#include "intl.h"
#include "langhooks.h"
+#include "contracts.h"
/* This TU doesn't need or want to see the networking. */
#define CODY_NETWORKING 0
#include "mapper-client.h"
@@ -6560,8 +6561,14 @@ trees_out::core_vals (tree t)
}
WT (t->function_decl.personality);
- WT (t->function_decl.function_specific_target);
- WT (t->function_decl.function_specific_optimization);
+ /* Rather than streaming target/optimize nodes, we should reconstruct
+ them on stream-in from any attributes applied to the function. */
+ if (streaming_p () && t->function_decl.function_specific_target)
+ warning_at (DECL_SOURCE_LOCATION (t), 0,
+ "%<target%> attribute currently unsupported in modules");
+ if (streaming_p () && t->function_decl.function_specific_optimization)
+ warning_at (DECL_SOURCE_LOCATION (t), 0,
+ "%<optimize%> attribute currently unsupported in modules");
WT (t->function_decl.vindex);
if (DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (t))
@@ -6651,11 +6658,12 @@ trees_out::core_vals (tree t)
case TARGET_OPTION_NODE:
// FIXME: Our representation for these two nodes is a cache of
// the resulting set of options. Not a record of the options
- // that got changed by a particular attribute or pragma. Should
- // we record that, or should we record the diff from the command
- // line options? The latter seems the right behaviour, but is
- // (a) harder, and I guess could introduce strangeness if the
- // importer has set some incompatible set of optimization flags?
+ // that got changed by a particular attribute or pragma. Instead
+ // of recording that, we probably should just rebuild the options
+ // on stream-in from the function attributes. This could introduce
+ // strangeness if the importer has some incompatible set of flags
+ // but we currently assume users "know what they're doing" in such
+ // a case anyway.
gcc_unreachable ();
break;
@@ -7114,8 +7122,10 @@ trees_in::core_vals (tree t)
}
RT (t->function_decl.personality);
- RT (t->function_decl.function_specific_target);
- RT (t->function_decl.function_specific_optimization);
+ /* These properties are not streamed, and should be reconstructed
+ from any function attributes. */
+ // t->function_decl.function_specific_target);
+ // t->function_decl.function_specific_optimization);
RT (t->function_decl.vindex);
if (DECL_HAS_DEPENDENT_EXPLICIT_SPEC_P (t))
@@ -7221,7 +7231,7 @@ trees_in::core_vals (tree t)
case OPTIMIZATION_NODE:
case TARGET_OPTION_NODE:
- /* Not yet implemented, see trees_out::core_vals. */
+ /* Not implemented, see trees_out::core_vals. */
gcc_unreachable ();
break;
@@ -11164,6 +11174,20 @@ trees_in::fn_parms_fini (int tag, tree fn, tree existing, bool is_defn)
names of the parms from us. */
DECL_NAME (existing_parm) = DECL_NAME (parm);
DECL_SOURCE_LOCATION (existing_parm) = DECL_SOURCE_LOCATION (parm);
+
+ /* And some other flags important for codegen are only set
+ by the definition. */
+ TREE_ADDRESSABLE (existing_parm) = TREE_ADDRESSABLE (parm);
+ DECL_BY_REFERENCE (existing_parm) = DECL_BY_REFERENCE (parm);
+ DECL_NONLOCAL (existing_parm) = DECL_NONLOCAL (parm);
+ DECL_ARG_TYPE (existing_parm) = DECL_ARG_TYPE (parm);
+
+ /* Invisiref parms had their types adjusted by cp_genericize. */
+ if (DECL_BY_REFERENCE (parm))
+ {
+ TREE_TYPE (existing_parm) = TREE_TYPE (parm);
+ relayout_decl (existing_parm);
+ }
}
back_refs[~tag] = existing_parm;
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index f5b36c9..ba62467 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -3351,8 +3351,12 @@ check_local_shadow (tree decl)
}
/* Don't complain if it's from an enclosing function. */
else if (DECL_CONTEXT (old) == current_function_decl
- && TREE_CODE (decl) != PARM_DECL
- && TREE_CODE (old) == PARM_DECL)
+ && ((TREE_CODE (decl) != PARM_DECL
+ && TREE_CODE (old) == PARM_DECL)
+ /* We should also give an error for
+ [x=1]{ int x; } */
+ || (is_capture_proxy (old)
+ && !is_normal_capture_proxy (old))))
{
/* Go to where the parms should be and see if we find
them there. */
@@ -3408,7 +3412,9 @@ check_local_shadow (tree decl)
detected elsewhere. */
else if (VAR_P (old)
&& old_scope == current_binding_level->level_chain
- && (old_scope->kind == sk_cond || old_scope->kind == sk_for))
+ && (old_scope->kind == sk_cond
+ || old_scope->kind == sk_for
+ || old_scope->kind == sk_template_for))
{
if (name_independent_decl_p (decl))
return old;
@@ -4626,6 +4632,7 @@ cp_binding_level_descriptor (cp_binding_level *scope)
"try-scope",
"catch-scope",
"for-scope",
+ "template-for-scope",
"cond-init-scope",
"stmt-expr-scope",
"function-parameter-scope",
@@ -4635,7 +4642,8 @@ cp_binding_level_descriptor (cp_binding_level *scope)
"template-parameter-scope",
"template-explicit-spec-scope",
"transaction-scope",
- "openmp-scope"
+ "openmp-scope",
+ "lambda-scope"
};
static_assert (ARRAY_SIZE (scope_kind_names) == sk_count,
"must keep names aligned with scope_kind enum");
@@ -4720,12 +4728,14 @@ begin_scope (scope_kind kind, tree entity)
case sk_try:
case sk_catch:
case sk_for:
+ case sk_template_for:
case sk_cond:
case sk_class:
case sk_scoped_enum:
case sk_transaction:
case sk_omp:
case sk_stmt_expr:
+ case sk_lambda:
scope->keep = keep_next_level_flag;
break;
@@ -5347,7 +5357,8 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
OVL_EXPORT_P (old.get_using ()) = true;
}
else if (!DECL_LANG_SPECIFIC (inner)
- || !DECL_MODULE_PURVIEW_P (inner))
+ || !DECL_MODULE_PURVIEW_P (inner)
+ || (exporting_p && !DECL_MODULE_EXPORT_P (inner)))
/* We need to re-insert this function as a revealed
(possibly exported) declaration. We can't remove
the existing decl because that will change any
@@ -5369,7 +5380,8 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
found = true;
if (revealing_p
&& (!DECL_LANG_SPECIFIC (inner)
- || !DECL_MODULE_PURVIEW_P (inner)))
+ || !DECL_MODULE_PURVIEW_P (inner)
+ || (exporting_p && !DECL_MODULE_EXPORT_P (inner))))
found = false;
break;
}
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 2fa736b..5b142e7 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -198,6 +198,7 @@ enum scope_kind {
sk_catch, /* A catch-block. */
sk_for, /* The scope of the variable declared in a
init-statement. */
+ sk_template_for, /* Ditto for expansion statements. */
sk_cond, /* The scope of the variable declared in the condition
of an if or switch statement. */
sk_stmt_expr, /* GNU statement expression block. */
@@ -214,6 +215,7 @@ enum scope_kind {
"template <>", this scope is always empty. */
sk_transaction, /* A synchronized or atomic statement. */
sk_omp, /* An OpenMP structured block. */
+ sk_lambda, /* A lambda scope. */
sk_count /* Number of scope_kind enumerations. */
};
@@ -287,7 +289,7 @@ struct GTY(()) cp_binding_level {
/* The kind of scope that this object represents. However, a
SK_TEMPLATE_SPEC scope is represented with KIND set to
SK_TEMPLATE_PARMS and EXPLICIT_SPEC_P set to true. */
- ENUM_BITFIELD (scope_kind) kind : 4;
+ ENUM_BITFIELD (scope_kind) kind : 5;
/* True if this scope is an SK_TEMPLATE_SPEC scope. This field is
only valid if KIND == SK_TEMPLATE_PARMS. */
@@ -315,7 +317,7 @@ struct GTY(()) cp_binding_level {
parent scope. */
unsigned artificial : 1;
- /* 21 bits left to fill a 32-bit word. */
+ /* 20 bits left to fill a 32-bit word. */
};
/* The binding level currently in effect. */
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 9e9cd9b..9f9bd56 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -601,6 +601,8 @@ cp_debug_parser (FILE *file, cp_parser *parser)
parser->in_template_argument_list_p);
cp_debug_print_flag (file, "Parsing an iteration statement",
parser->in_statement & IN_ITERATION_STMT);
+ cp_debug_print_flag (file, "Parsing an expansion statement",
+ parser->in_statement & IN_EXPANSION_STMT);
cp_debug_print_flag (file, "Parsing a switch statement",
parser->in_statement & IN_SWITCH_STMT);
cp_debug_print_flag (file, "Parsing a structured OpenMP block",
@@ -2576,11 +2578,11 @@ static cp_expr cp_parser_constant_expression
static cp_expr cp_parser_builtin_offsetof
(cp_parser *);
static cp_expr cp_parser_lambda_expression
- (cp_parser *);
+ (cp_parser *, bool = false);
static void cp_parser_lambda_introducer
(cp_parser *, tree);
static bool cp_parser_lambda_declarator_opt
- (cp_parser *, tree);
+ (cp_parser *, tree, bool = false);
static void cp_parser_lambda_body
(cp_parser *, tree);
@@ -2611,11 +2613,11 @@ static tree cp_parser_c_for
static tree cp_parser_range_for
(cp_parser *, tree, tree, tree, bool, tree, bool, bool);
static void do_range_for_auto_deduction
- (tree, tree, cp_decomp *);
-static tree cp_parser_perform_range_for_lookup
- (tree, tree *, tree *);
-static tree cp_parser_range_for_member_function
+ (tree, tree, cp_decomp *, bool);
+static tree cp_range_for_member_function
(tree, tree);
+static tree cp_parser_expansion_statement
+ (cp_parser *, bool *);
static tree cp_parser_jump_statement
(cp_parser *, tree &);
static void cp_parser_declaration_statement
@@ -2921,7 +2923,7 @@ static size_t cp_parser_skip_std_attribute_spec_seq
static size_t cp_parser_skip_attributes_opt
(cp_parser *, size_t);
static bool cp_parser_extension_opt
- (cp_parser *, int *);
+ (cp_parser *, int *, int *);
static void cp_parser_label_declaration
(cp_parser *);
@@ -9504,11 +9506,12 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
case RID_EXTENSION:
{
/* The saved value of the PEDANTIC flag. */
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
tree expr;
/* Save away the PEDANTIC flag. */
- cp_parser_extension_opt (parser, &saved_pedantic);
+ cp_parser_extension_opt (parser, &saved_pedantic,
+ &saved_long_long);
/* Also suppress -Wconditionally-supported. */
diagnostic_push_diagnostics (global_dc, input_location);
diagnostic_classify_diagnostic
@@ -9519,6 +9522,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
/* Restore the PEDANTIC flag. */
diagnostic_pop_diagnostics (global_dc, input_location);
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return expr;
}
@@ -11742,10 +11746,14 @@ cp_parser_trait (cp_parser* parser, const cp_trait* trait)
lambda-introducer < template-parameter-list > requires-clause [opt]
lambda-declarator [opt] compound-statement
+ If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which
+ is syntactic sugar for a consteval lambda.
+
Returns a representation of the expression. */
static cp_expr
-cp_parser_lambda_expression (cp_parser* parser)
+cp_parser_lambda_expression (cp_parser* parser,
+ bool consteval_block_p/*=false*/)
{
tree lambda_expr = build_lambda_expr ();
tree type;
@@ -11754,6 +11762,7 @@ cp_parser_lambda_expression (cp_parser* parser)
cp_token_position start = 0;
LAMBDA_EXPR_LOCATION (lambda_expr) = token->location;
+ LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lambda_expr) = consteval_block_p;
if (cxx_dialect >= cxx20)
{
@@ -11797,9 +11806,14 @@ cp_parser_lambda_expression (cp_parser* parser)
it now. */
push_deferring_access_checks (dk_no_deferred);
- cp_parser_lambda_introducer (parser, lambda_expr);
- if (cp_parser_error_occurred (parser))
- return error_mark_node;
+ auto gr = make_temp_override (parser->greater_than_is_operator_p, true);
+
+ if (!consteval_block_p)
+ {
+ cp_parser_lambda_introducer (parser, lambda_expr);
+ if (cp_parser_error_occurred (parser))
+ return error_mark_node;
+ }
{
/* OK, this is a bit tricksy. cp_parser_requires_expression sets
@@ -11865,13 +11879,22 @@ cp_parser_lambda_expression (cp_parser* parser)
bool save_in_consteval_if_p = in_consteval_if_p;
in_consteval_if_p = false;
+ /* Similarly the body of a lambda is not part of expansion statement. */
+ bool save_in_expansion_stmt = in_expansion_stmt;
+ in_expansion_stmt = 0;
+
/* By virtue of defining a local class, a lambda expression has access to
the private variables of enclosing classes. */
if (cp_parser_start_tentative_firewall (parser))
start = token;
- ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr);
+ /* A lambda scope starts immediately after the lambda-introducer of E
+ and extends to the end of the compound-statement of E. */
+ begin_scope (sk_lambda, NULL_TREE);
+
+ ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr,
+ consteval_block_p);
if (ok && cp_parser_error_occurred (parser))
ok = false;
@@ -11891,8 +11914,11 @@ cp_parser_lambda_expression (cp_parser* parser)
if (ok)
maybe_add_lambda_conv_op (type);
+ /* Leave the lambda scope. */
+ pop_bindings_and_leave_scope ();
finish_struct (type, /*attributes=*/NULL_TREE);
+ in_expansion_stmt = save_in_expansion_stmt;
in_consteval_if_p = save_in_consteval_if_p;
in_discarded_stmt = discarded;
@@ -12254,10 +12280,13 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
decl-specifier-seq [opt] noexcept-specifier [opt]
attribute-specifier-seq [opt] trailing-return-type [opt]
- LAMBDA_EXPR is the current representation of the lambda expression. */
+ LAMBDA_EXPR is the current representation of the lambda expression.
+ If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which
+ is syntactic sugar for a consteval lambda. */
static bool
-cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
+cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr,
+ bool consteval_block_p/*=false*/)
{
/* 5.1.1.4 of the standard says:
If a lambda-expression does not include a lambda-declarator, it is as if
@@ -12278,6 +12307,13 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
clear_decl_specs (&lambda_specs);
/* A lambda op() is const unless explicitly 'mutable'. */
cp_cv_quals quals = TYPE_QUAL_CONST;
+ /* Don't add "const" to entities in the parameter-declaration-clause. */
+ LAMBDA_EXPR_CONST_QUAL_P (lambda_expr) = false;
+
+ /* Inject the captures into the lambda scope as they may be used in the
+ declarator and we have to be able to look them up. */
+ tree dummy_fco = maybe_add_dummy_lambda_op (lambda_expr);
+ push_capture_proxies (lambda_expr, /*early_p=*/true);
/* The template-parameter-list is optional, but must begin with
an opening angle if present. */
@@ -12360,6 +12396,18 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
&lambda_specs, &declares_class_or_enum);
+ /* [dcl.pre] For a consteval-block-declaration D, the expression E
+ corresponding to D is:
+ [] -> void static consteval compound-statement ()
+ Make it so. */
+ if (consteval_block_p)
+ {
+ return_type = void_type_node;
+ lambda_specs.storage_class = sc_static;
+ set_and_check_decl_spec_loc (&lambda_specs, ds_consteval,
+ cp_lexer_peek_token (parser->lexer));
+ }
+
if (omitted_parms_loc && lambda_specs.any_specifiers_p)
{
pedwarn (omitted_parms_loc, OPT_Wc__23_extensions,
@@ -12456,6 +12504,10 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
}
}
+ /* Now we're done with the parameter-declaration-clause, and should
+ assume "const" unless "mutable" was present. */
+ LAMBDA_EXPR_CONST_QUAL_P (lambda_expr) = quals == TYPE_QUAL_CONST;
+
tx_qual = cp_parser_tx_qualifier_opt (parser);
if (omitted_parms_loc && tx_qual)
{
@@ -12513,6 +12565,10 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
pop_bindings_and_leave_scope ();
}
+ /* We are about to create the real operator(), so get rid of the old one. */
+ if (dummy_fco)
+ remove_dummy_lambda_op (dummy_fco, lambda_expr);
+
/* Create the function call operator.
Messing with declarators like this is no uglier than building up the
@@ -12592,6 +12648,79 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
}
}
+/* Create a fake operator() for a lambda. We do this so that we can
+ build_capture_proxy even before start_lambda_function. */
+
+static tree
+make_dummy_lambda_op ()
+{
+ cp_decl_specifier_seq return_type_specs;
+ cp_cv_quals quals = TYPE_UNQUALIFIED;
+
+ clear_decl_specs (&return_type_specs);
+ return_type_specs.type = make_auto ();
+
+ void *p = obstack_alloc (&declarator_obstack, 0);
+
+ cp_declarator *declarator = make_id_declarator (NULL_TREE,
+ call_op_identifier,
+ sfk_none,
+ input_location);
+
+ declarator = make_call_declarator (declarator, void_list_node, quals,
+ VIRT_SPEC_UNSPECIFIED,
+ REF_QUAL_NONE, NULL_TREE,
+ NULL_TREE, NULL_TREE, NULL_TREE,
+ NULL_TREE, UNKNOWN_LOCATION);
+
+ tree fco = grokmethod (&return_type_specs, declarator, NULL_TREE);
+ obstack_free (&declarator_obstack, p);
+
+ return fco;
+}
+
+/* We need to push early capture proxies (for parsing the lambda-declarator),
+ and we may need a dummy operator() to be able to build the proxies.
+ LAMBDA_EXPR is the lambda we are building the captures for. */
+
+tree
+maybe_add_dummy_lambda_op (tree lambda_expr)
+{
+ /* If there are no captures, we don't need this. */
+ if (!LAMBDA_EXPR_CAPTURE_LIST (lambda_expr))
+ return NULL_TREE;
+
+ tree fco = make_dummy_lambda_op ();
+ if (fco != error_mark_node)
+ finish_member_declaration (fco);
+
+ return fco;
+}
+
+/* Remove the dummy operator() DUMMY_FCO we built for parsing the
+ lambda-declarator of LAMBDA_EXPR. */
+
+void
+remove_dummy_lambda_op (tree dummy_fco, tree lambda_expr)
+{
+ tree type = TREE_TYPE (lambda_expr);
+ if (TYPE_FIELDS (type) == dummy_fco)
+ {
+ /* Stitch out the dummy operator(). */
+ TYPE_FIELDS (type) = DECL_CHAIN (TYPE_FIELDS (type));
+ /* And clear the member vector as well. */
+ auto *member_vec = CLASSTYPE_MEMBER_VEC (type);
+ gcc_assert (member_vec->length () == 1);
+ member_vec->truncate (0);
+ }
+ /* Class templates will have the dummy operator() stashed here too. */
+ tree &list = CLASSTYPE_DECL_LIST (type);
+ if (list && TREE_VALUE (list) == dummy_fco)
+ list = TREE_CHAIN (list);
+ /* ??? We can't ggc_free dummy_fco yet. There's still a binding in the
+ closure to it, and the captures have it as their DECL_CONTEXT. */
+}
+
/* Parse the body of a lambda expression, which is simply
compound-statement
@@ -13138,6 +13267,11 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
case RID_TRANSACTION_CANCEL:
handle_omp_attribs = true;
break;
+ case RID_TEMPLATE:
+ if (cxx_dialect >= cxx11
+ && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR))
+ handle_omp_attribs = true;
+ break;
default:
break;
}
@@ -13190,6 +13324,16 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
NULL_TREE, false);
break;
+ case RID_TEMPLATE:
+ if (cxx_dialect >= cxx11
+ && cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR))
+ {
+ std_attrs = process_stmt_hotness_attribute (std_attrs,
+ attrs_loc);
+ statement = cp_parser_expansion_statement (parser, if_p);
+ }
+ break;
+
case RID_BREAK:
case RID_CONTINUE:
case RID_RETURN:
@@ -13592,6 +13736,13 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
default:
/* Anything else must be an ordinary label. */
cp_expr identifier = cp_parser_identifier (parser);
+ if (in_expansion_stmt && identifier != error_mark_node)
+ {
+ error_at (token->location,
+ "identifier label %qE in %<template for%> body",
+ *identifier);
+ break;
+ }
if (identifier != error_mark_node
&& parser->omp_metadirective_state)
*identifier = mangle_metadirective_region_label (parser, *identifier);
@@ -14618,6 +14769,73 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep,
return stmt;
}
+/* Helper function for cp_parser_range_for and cp_parser_expansion_statement.
+ Get the range declaration momentarily out of the way so that the range
+ expression doesn't clash with it. */
+
+static cp_decomp *
+cp_hide_range_decl (tree *range_decl_p, cp_decomp *decomp_d,
+ auto_vec <cxx_binding *> &bindings,
+ auto_vec <tree> &names)
+{
+ tree range_decl = *range_decl_p;
+ cp_decomp *decomp = NULL;
+ if (range_decl == error_mark_node)
+ return decomp;
+
+ if (DECL_HAS_VALUE_EXPR_P (range_decl))
+ {
+ tree v = DECL_VALUE_EXPR (range_decl);
+ /* For decomposition declaration get all of the corresponding
+ declarations out of the way. */
+ if ((TREE_CODE (v) == ARRAY_REF
+ && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+ || (TREE_CODE (v) == TREE_VEC
+ && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0))))
+ {
+ tree d = range_decl;
+ decomp = decomp_d;
+ if (TREE_CODE (v) == ARRAY_REF)
+ {
+ *range_decl_p = range_decl = TREE_OPERAND (v, 0);
+ decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
+ }
+ else
+ {
+ *range_decl_p = range_decl = TREE_VEC_ELT (v, 0);
+ decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1;
+ }
+ decomp->decl = d;
+ bool seen_name_independent_decl = false;
+ names.reserve (decomp->count);
+ bindings.reserve (decomp->count);
+ for (unsigned int i = 0; i < decomp->count; i++, d = DECL_CHAIN (d))
+ {
+ if (name_independent_decl_p (d))
+ {
+ /* If there is more than one _ decl in the structured
+ binding, just push and move it away once. */
+ if (seen_name_independent_decl)
+ continue;
+ seen_name_independent_decl = true;
+ }
+ tree name = DECL_NAME (d);
+ names.quick_push (name);
+ bindings.quick_push (IDENTIFIER_BINDING (name));
+ IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous;
+ }
+ }
+ }
+ if (names.is_empty ())
+ {
+ tree name = DECL_NAME (range_decl);
+ names.safe_push (name);
+ bindings.safe_push (IDENTIFIER_BINDING (name));
+ IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous;
+ }
+ return decomp;
+}
+
/* Tries to parse a range-based for-statement:
range-based-for:
@@ -14633,56 +14851,14 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
bool ivdep, tree unroll, bool novector, bool is_omp)
{
tree stmt, range_expr;
- auto_vec <cxx_binding *, 16> bindings;
- auto_vec <tree, 16> names;
- cp_decomp decomp_d, *decomp = NULL;
+ auto_vec <cxx_binding *> bindings;
+ auto_vec <tree> names;
+ cp_decomp decomp_d;
/* Get the range declaration momentarily out of the way so that
the range expression doesn't clash with it. */
- if (range_decl != error_mark_node)
- {
- if (DECL_HAS_VALUE_EXPR_P (range_decl))
- {
- tree v = DECL_VALUE_EXPR (range_decl);
- /* For decomposition declaration get all of the corresponding
- declarations out of the way. */
- if (TREE_CODE (v) == ARRAY_REF
- && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
- {
- tree d = range_decl;
- range_decl = TREE_OPERAND (v, 0);
- decomp = &decomp_d;
- decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
- decomp->decl = d;
- bool seen_name_independent_decl = false;
- for (unsigned int i = 0; i < decomp->count;
- i++, d = DECL_CHAIN (d))
- {
- if (name_independent_decl_p (d))
- {
- /* If there is more than one _ decl in
- the structured binding, just push and move it
- away once. */
- if (seen_name_independent_decl)
- continue;
- seen_name_independent_decl = true;
- }
- tree name = DECL_NAME (d);
- names.safe_push (name);
- bindings.safe_push (IDENTIFIER_BINDING (name));
- IDENTIFIER_BINDING (name)
- = IDENTIFIER_BINDING (name)->previous;
- }
- }
- }
- if (names.is_empty ())
- {
- tree name = DECL_NAME (range_decl);
- names.safe_push (name);
- bindings.safe_push (IDENTIFIER_BINDING (name));
- IDENTIFIER_BINDING (name) = IDENTIFIER_BINDING (name)->previous;
- }
- }
+ cp_decomp *decomp = cp_hide_range_decl (&range_decl, &decomp_d, bindings,
+ names);
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
range_expr = cp_parser_braced_list (parser);
@@ -14719,7 +14895,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
if (!type_dependent_expression_p (range_expr)
/* do_auto_deduction doesn't mess with template init-lists. */
&& !BRACE_ENCLOSED_INITIALIZER_P (range_expr))
- do_range_for_auto_deduction (range_decl, range_expr, decomp);
+ do_range_for_auto_deduction (range_decl, range_expr, decomp, false);
}
else
{
@@ -14733,7 +14909,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
/* Subroutine of cp_convert_range_for: given the initializer expression,
builds up the range temporary. */
-static tree
+tree
build_range_temp (tree range_expr)
{
/* Find out the type deduced by the declaration
@@ -14757,15 +14933,22 @@ build_range_temp (tree range_expr)
a shortcut version of cp_convert_range_for. */
static void
-do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp)
+do_range_for_auto_deduction (tree decl, tree range_expr, cp_decomp *decomp,
+ bool expansion_stmt)
{
tree auto_node = type_uses_auto (TREE_TYPE (decl));
if (auto_node)
{
tree begin_dummy, end_dummy, range_temp, iter_type, iter_decl;
range_temp = convert_from_reference (build_range_temp (range_expr));
- iter_type = (cp_parser_perform_range_for_lookup
- (range_temp, &begin_dummy, &end_dummy));
+ iter_type = cp_perform_range_for_lookup (range_temp, &begin_dummy,
+ &end_dummy,
+ expansion_stmt ? tf_none
+ : tf_warning_or_error);
+ if (expansion_stmt
+ && (begin_dummy == error_mark_node
+ || end_dummy == error_mark_node))
+ return;
if (iter_type)
{
iter_decl = build_decl (input_location, VAR_DECL, NULL_TREE,
@@ -14866,6 +15049,89 @@ warn_for_range_copy (tree decl, tree expr)
}
}
+/* Helper function for cp_convert_range_for and finish_expansion_stmt.
+ Build the __range, __begin and __end declarations. Return the
+ __begin VAR_DECL, set *END_P to the __end VAR_DECL. */
+
+tree
+cp_build_range_for_decls (location_t loc, tree range_expr, tree *end_p,
+ bool expansion_stmt_p)
+{
+ tree iter_type, begin_expr, end_expr;
+
+ if (range_expr == error_mark_node)
+ /* If an error happened previously do nothing or else a lot of
+ unhelpful errors would be issued. */
+ begin_expr = end_expr = iter_type = error_mark_node;
+ else
+ {
+ tree range_temp;
+
+ if (!expansion_stmt_p
+ && VAR_P (range_expr)
+ && array_of_runtime_bound_p (TREE_TYPE (range_expr)))
+ /* Can't bind a reference to an array of runtime bound. */
+ range_temp = range_expr;
+ else
+ {
+ range_temp = build_range_temp (range_expr);
+ if (expansion_stmt_p)
+ {
+ /* Depending on CWG3044 resolution, we might want to remove
+ these 3 sets of TREE_STATIC (on range_temp, begin and end).
+ Although it can only be done when P2686R4 is fully
+ implemented. */
+ TREE_STATIC (range_temp) = 1;
+ TREE_PUBLIC (range_temp) = 0;
+ DECL_COMMON (range_temp) = 0;
+ DECL_INTERFACE_KNOWN (range_temp) = 1;
+ DECL_DECLARED_CONSTEXPR_P (range_temp) = 1;
+ TREE_READONLY (range_temp) = 1;
+ }
+ pushdecl (range_temp);
+ cp_finish_decl (range_temp, range_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+ range_temp = convert_from_reference (range_temp);
+ }
+ iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr,
+ &end_expr);
+ }
+
+ /* The new for initialization statement. */
+ tree begin = build_decl (loc, VAR_DECL, for_begin__identifier, iter_type);
+ TREE_USED (begin) = 1;
+ DECL_ARTIFICIAL (begin) = 1;
+ if (expansion_stmt_p)
+ {
+ TREE_STATIC (begin) = 1;
+ DECL_DECLARED_CONSTEXPR_P (begin) = 1;
+ TREE_READONLY (begin) = 1;
+ }
+ pushdecl (begin);
+ cp_finish_decl (begin, begin_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+
+ if (cxx_dialect >= cxx17)
+ iter_type = cv_unqualified (TREE_TYPE (end_expr));
+ tree end = build_decl (loc, VAR_DECL, for_end__identifier, iter_type);
+ TREE_USED (end) = 1;
+ DECL_ARTIFICIAL (end) = 1;
+ if (expansion_stmt_p)
+ {
+ TREE_STATIC (end) = 1;
+ DECL_DECLARED_CONSTEXPR_P (end) = 1;
+ TREE_READONLY (end) = 1;
+ }
+ pushdecl (end);
+ cp_finish_decl (end, end_expr,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+ *end_p = end;
+ return begin;
+}
+
/* Converts a range-based for-statement into a normal
for-statement, as per the definition.
@@ -14906,56 +15172,14 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
cp_decomp *decomp, bool ivdep, tree unroll,
bool novector)
{
- tree begin, end;
- tree iter_type, begin_expr, end_expr;
- tree condition, expression;
+ tree end, condition, expression;
range_expr = mark_lvalue_use (range_expr);
- if (range_decl == error_mark_node || range_expr == error_mark_node)
- /* If an error happened previously do nothing or else a lot of
- unhelpful errors would be issued. */
- begin_expr = end_expr = iter_type = error_mark_node;
- else
- {
- tree range_temp;
-
- if (VAR_P (range_expr)
- && array_of_runtime_bound_p (TREE_TYPE (range_expr)))
- /* Can't bind a reference to an array of runtime bound. */
- range_temp = range_expr;
- else
- {
- range_temp = build_range_temp (range_expr);
- pushdecl (range_temp);
- cp_finish_decl (range_temp, range_expr,
- /*is_constant_init*/false, NULL_TREE,
- LOOKUP_ONLYCONVERTING);
- range_temp = convert_from_reference (range_temp);
- }
- iter_type = cp_parser_perform_range_for_lookup (range_temp,
- &begin_expr, &end_expr);
- }
-
- /* The new for initialization statement. */
- begin = build_decl (input_location, VAR_DECL, for_begin__identifier,
- iter_type);
- TREE_USED (begin) = 1;
- DECL_ARTIFICIAL (begin) = 1;
- pushdecl (begin);
- cp_finish_decl (begin, begin_expr,
- /*is_constant_init*/false, NULL_TREE,
- LOOKUP_ONLYCONVERTING);
-
- if (cxx_dialect >= cxx17)
- iter_type = cv_unqualified (TREE_TYPE (end_expr));
- end = build_decl (input_location, VAR_DECL, for_end__identifier, iter_type);
- TREE_USED (end) = 1;
- DECL_ARTIFICIAL (end) = 1;
- pushdecl (end);
- cp_finish_decl (end, end_expr,
- /*is_constant_init*/false, NULL_TREE,
- LOOKUP_ONLYCONVERTING);
+ if (range_decl == error_mark_node)
+ range_expr = error_mark_node;
+ tree begin
+ = cp_build_range_for_decls (input_location, range_expr, &end, false);
finish_init_stmt (statement);
@@ -14989,8 +15213,10 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
depends on the existence of members begin or end.
Returns the type deduced for the iterator expression. */
-static tree
-cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
+tree
+cp_perform_range_for_lookup (tree range, tree *begin, tree *end,
+ tsubst_flags_t complain
+ /* = tf_warning_or_error */)
{
if (error_operand_p (range))
{
@@ -15000,8 +15226,9 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (range))))
{
- error ("range-based %<for%> expression of type %qT "
- "has incomplete type", TREE_TYPE (range));
+ if (complain & tf_error)
+ error ("range-based %<for%> expression of type %qT "
+ "has incomplete type", TREE_TYPE (range));
*begin = *end = error_mark_node;
return error_mark_node;
}
@@ -15027,16 +15254,16 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
id_end = get_identifier ("end");
member_begin = lookup_member (TREE_TYPE (range), id_begin,
/*protect=*/2, /*want_type=*/false,
- tf_warning_or_error);
+ complain);
member_end = lookup_member (TREE_TYPE (range), id_end,
/*protect=*/2, /*want_type=*/false,
- tf_warning_or_error);
+ complain);
if (member_begin != NULL_TREE && member_end != NULL_TREE)
{
/* Use the member functions. */
- *begin = cp_parser_range_for_member_function (range, id_begin);
- *end = cp_parser_range_for_member_function (range, id_end);
+ *begin = cp_range_for_member_function (range, id_begin);
+ *end = cp_range_for_member_function (range, id_end);
}
else
{
@@ -15046,13 +15273,20 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
vec_safe_push (vec, range);
member_begin = perform_koenig_lookup (id_begin, vec,
- tf_warning_or_error);
+ complain);
+ if ((complain & tf_error) == 0 && member_begin == id_begin)
+ return error_mark_node;
*begin = finish_call_expr (member_begin, &vec, false, true,
- tf_warning_or_error);
+ complain);
member_end = perform_koenig_lookup (id_end, vec,
tf_warning_or_error);
+ if ((complain & tf_error) == 0 && member_end == id_end)
+ {
+ *begin = error_mark_node;
+ return error_mark_node;
+ }
*end = finish_call_expr (member_end, &vec, false, true,
- tf_warning_or_error);
+ complain);
}
/* Last common checks. */
@@ -15083,7 +15317,7 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
/* P0184R0 allows __begin and __end to have different types,
but make sure they are comparable so we can give a better
diagnostic. */;
- else
+ else if (complain & tf_error)
error ("inconsistent begin/end types in range-based %<for%> "
"statement: %qT and %qT",
TREE_TYPE (*begin), TREE_TYPE (*end));
@@ -15093,11 +15327,11 @@ cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
}
}
-/* Helper function for cp_parser_perform_range_for_lookup.
+/* Helper function for cp_perform_range_for_lookup.
Builds a tree for RANGE.IDENTIFIER(). */
static tree
-cp_parser_range_for_member_function (tree range, tree identifier)
+cp_range_for_member_function (tree range, tree identifier)
{
tree member, res;
@@ -15316,6 +15550,183 @@ cp_parser_init_statement (cp_parser *parser, tree *decl)
return false;
}
+/* Parse an expansion-statement.
+
+ expansion-statement:
+ template for ( init-statement[opt]
+ for-range-declaration : expansion-initializer )
+ statement
+
+ expansion-initializer:
+ expression
+ expansion-init-list
+
+ expansion-init-list:
+ { expression-list } */
+
+static tree
+cp_parser_expansion_statement (cp_parser* parser, bool *if_p)
+{
+ /* Peek at the next token. */
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ gcc_assert (token->keyword == RID_TEMPLATE);
+ gcc_assert (cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_FOR));
+ cp_lexer_consume_token (parser->lexer);
+ cp_token *for_token = cp_lexer_peek_token (parser->lexer);
+ cp_lexer_consume_token (parser->lexer);
+
+ if (cxx_dialect < cxx26)
+ pedwarn (make_location (token->location, token->location,
+ for_token->location), OPT_Wc__26_extensions,
+ "%<template for%> only available with %<-std=c++2c%> "
+ "or %<-std=gnu++2c%>");
+
+ token_indent_info guard_tinfo = get_token_indent_info (token);
+
+ /* Remember whether or not we are already within an iteration
+ statement. */
+ unsigned char in_statement = parser->in_statement;
+ /* And whether we are already in expansion-statement. */
+ auto save_in_expansion_stmt = in_expansion_stmt;
+
+ /* Look for the `('. */
+ matching_parens parens;
+ parens.require_open (parser);
+
+ tree init;
+ tree scope = begin_template_for_scope (&init);
+
+ /* Maybe parse the optional init-statement in a expansion-statement. */
+ if (cp_parser_range_based_for_with_init_p (parser)
+ /* Checked for diagnostic purposes only. */
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ {
+ tree dummy;
+ cp_parser_init_statement (parser, &dummy);
+ }
+
+ bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+
+ /* A colon is used in expansion-statement. */
+ parser->colon_corrects_to_scope_p = false;
+
+ /* Parse the declaration. */
+ tree range_decl;
+ cp_parser_simple_declaration (parser,
+ /*function_definition_allowed_p=*/false,
+ &range_decl);
+ if (range_decl == NULL_TREE)
+ range_decl = error_mark_node;
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+
+ cp_parser_require (parser, CPP_COLON, RT_COLON);
+
+ auto_vec <cxx_binding *> bindings;
+ auto_vec <tree> names;
+ cp_decomp decomp_d;
+
+ /* Get the range declaration momentarily out of the way so that
+ the range expression doesn't clash with it. */
+ cp_decomp *decomp = cp_hide_range_decl (&range_decl, &decomp_d, bindings,
+ names);
+
+ tree expansion_init;
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ {
+ expansion_init = cp_parser_braced_list (parser);
+ if (TREE_CODE (expansion_init) == CONSTRUCTOR
+ && CONSTRUCTOR_IS_DESIGNATED_INIT (expansion_init))
+ error_at (EXPR_LOC_OR_LOC (expansion_init, token->location),
+ "designators in %<template for%> initializer");
+ }
+ else
+ expansion_init = cp_parser_expression (parser);
+
+ /* Put the range declaration(s) back into scope. */
+ for (unsigned int i = 0; i < names.length (); i++)
+ {
+ cxx_binding *binding = bindings[i];
+ binding->previous = IDENTIFIER_BINDING (names[i]);
+ IDENTIFIER_BINDING (names[i]) = binding;
+ }
+
+ /* Look for the `)'. */
+ parens.require_close (parser);
+
+ if (processing_template_decl
+ && check_for_bare_parameter_packs (expansion_init))
+ expansion_init = error_mark_node;
+
+ if (expansion_init != error_mark_node
+ && !type_dependent_expression_p (expansion_init)
+ && TREE_CODE (TREE_TYPE (expansion_init)) != ARRAY_TYPE
+ && !BRACE_ENCLOSED_INITIALIZER_P (expansion_init))
+ do_range_for_auto_deduction (range_decl, expansion_init, decomp,
+ true);
+
+ bool outside_of_template = !processing_template_decl;
+ if (outside_of_template)
+ {
+ ++processing_template_decl;
+ current_template_parms
+ = tree_cons (size_int (current_template_depth + 1),
+ make_tree_vec (0), current_template_parms);
+ }
+ in_expansion_stmt = true;
+
+ tree r = build_stmt (token->location, TEMPLATE_FOR_STMT, NULL_TREE,
+ NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
+
+ current_binding_level->this_entity = r;
+ TEMPLATE_FOR_INIT_STMT (r) = init;
+ TEMPLATE_FOR_SCOPE (r) = scope;
+ if (!outside_of_template)
+ TEMPLATE_FOR_INIT_STMT (r) = pop_stmt_list (TEMPLATE_FOR_INIT_STMT (r));
+ TEMPLATE_FOR_DECL (r) = range_decl;
+ TEMPLATE_FOR_EXPR (r) = expansion_init;
+ TEMPLATE_FOR_BODY (r) = do_pushlevel (sk_block);
+
+ /* Parse the body of the expansion-statement. */
+ parser->in_statement = IN_EXPANSION_STMT;
+ bool prev = note_iteration_stmt_body_start ();
+ cp_parser_already_scoped_statement (parser, if_p, guard_tinfo);
+ note_iteration_stmt_body_end (prev);
+ parser->in_statement = in_statement;
+ in_expansion_stmt = save_in_expansion_stmt;
+
+ TEMPLATE_FOR_BODY (r) = do_poplevel (TEMPLATE_FOR_BODY (r));
+
+ if (outside_of_template)
+ {
+ current_template_parms = TREE_CHAIN (current_template_parms);
+ --processing_template_decl;
+ }
+
+ if (VAR_P (range_decl) && DECL_DECLARED_CONSTINIT_P (range_decl))
+ error_at (DECL_SOURCE_LOCATION (range_decl),
+ "for-range-declaration cannot be 'constinit'");
+
+ if (decomp)
+ {
+ tree v = make_tree_vec (decomp->count + 1);
+ TREE_VEC_ELT (v, 0) = TEMPLATE_FOR_DECL (r);
+ tree d = decomp->decl;
+ for (unsigned i = 0; i < decomp->count; ++i, d = DECL_CHAIN (d))
+ TREE_VEC_ELT (v, decomp->count - i) = d;
+ TEMPLATE_FOR_DECL (r) = v;
+ }
+
+ if (processing_template_decl)
+ add_stmt (r);
+ else
+ finish_expansion_stmt (r, NULL_TREE, tf_warning_or_error, NULL_TREE);
+
+ add_stmt (do_poplevel (TEMPLATE_FOR_SCOPE (r)));
+ TEMPLATE_FOR_SCOPE (r) = NULL_TREE;
+
+ return r;
+}
+
/* Parse a jump-statement.
jump-statement:
@@ -15360,7 +15771,8 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs)
break;
default:
gcc_assert ((in_statement & IN_SWITCH_STMT)
- || in_statement == IN_ITERATION_STMT);
+ || in_statement == IN_ITERATION_STMT
+ || in_statement == IN_EXPANSION_STMT);
statement = finish_break_stmt ();
if (in_statement == IN_ITERATION_STMT)
break_maybe_infinite_loop ();
@@ -15383,6 +15795,7 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs)
break;
/* Fall through. */
case IN_ITERATION_STMT:
+ case IN_EXPANSION_STMT:
case IN_OMP_FOR:
statement = finish_continue_stmt ();
break;
@@ -16047,15 +16460,16 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
static void
cp_parser_declaration (cp_parser* parser, tree prefix_attrs)
{
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
/* Check for the `__extension__' keyword. */
- if (cp_parser_extension_opt (parser, &saved_pedantic))
+ if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long))
{
/* Parse the qualified declaration. */
cp_parser_declaration (parser, prefix_attrs);
/* Restore the PEDANTIC flag. */
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return;
}
@@ -16297,6 +16711,56 @@ cp_parser_toplevel_declaration (cp_parser* parser)
cp_parser_declaration (parser, NULL_TREE);
}
+/* Build an empty string for static_assert. */
+
+static tree
+build_empty_string ()
+{
+ tree message = build_string (1, "");
+ TREE_TYPE (message) = char_array_type_node;
+ fix_string_type (message);
+ return message;
+}
+
+/* Return true iff the next tokens start a C++26 consteval block. */
+
+static bool
+cp_parser_next_tokens_are_consteval_block_p (cp_parser *parser)
+{
+ return (cxx_dialect >= cxx26
+ && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONSTEVAL)
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_BRACE));
+}
+
+/* Parse a consteval-block-declaration.
+
+ consteval-block-declaration:
+ consteval compound-statement
+
+ If MEMBER_P, this consteval block is a member declaration. */
+
+static void
+cp_parser_consteval_block (cp_parser *parser, bool member_p)
+{
+ const location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ /* Consume the 'consteval'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* We know the next token is '{'. Let cp_parser_lambda_body handle it. */
+ cp_expr lam = cp_parser_lambda_expression (parser,
+ /*consteval_block_p=*/true);
+ if (!cp_parser_error_occurred (parser))
+ {
+ releasing_vec args;
+ tree call = finish_call_expr (lam, &args,
+ /*disallow_virtual=*/false,
+ /*koenig_p=*/false,
+ tf_warning_or_error);
+ finish_static_assert (call, build_empty_string (), loc, member_p,
+ /*show_expr_p=*/false, /*consteval_block_p=*/true);
+ }
+}
+
/* Parse a block-declaration.
block-declaration:
@@ -16304,18 +16768,18 @@ cp_parser_toplevel_declaration (cp_parser* parser)
asm-definition
namespace-alias-definition
using-declaration
+ using-enum-declaration
using-directive
+ static_assert-declaration
+ consteval-block-declaration
+ alias-declaration
+ opaque-enum-declaration
GNU Extension:
block-declaration:
__extension__ block-declaration
- C++0x Extension:
-
- block-declaration:
- static_assert-declaration
-
If STATEMENT_P is TRUE, then this block-declaration is occurring as
part of a declaration-statement. */
@@ -16323,15 +16787,16 @@ static void
cp_parser_block_declaration (cp_parser *parser,
bool statement_p)
{
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
/* Check for the `__extension__' keyword. */
- if (cp_parser_extension_opt (parser, &saved_pedantic))
+ if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long))
{
/* Parse the qualified declaration. */
cp_parser_block_declaration (parser, statement_p);
/* Restore the PEDANTIC flag. */
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return;
}
@@ -16392,6 +16857,8 @@ 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);
+ else if (cp_parser_next_tokens_are_consteval_block_p (parser))
+ cp_parser_consteval_block (parser, /*member_p=*/false);
else
{
size_t attr_idx = cp_parser_skip_std_attribute_spec_seq (parser, 1);
@@ -16763,7 +17230,7 @@ cp_parser_simple_declaration (cp_parser* parser,
}
/* Helper of cp_parser_simple_declaration, parse a decomposition declaration.
- decl-specifier-seq ref-qualifier [opt] [ identifier-list ]
+ decl-specifier-seq ref-qualifier [opt] [ sb-identifier-list ]
initializer ; */
static tree
@@ -16776,21 +17243,45 @@ cp_parser_decomposition_declaration (cp_parser *parser,
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE);
- /* Parse the identifier-list. */
+ /* Parse the sb-identifier-list. */
auto_vec<cp_expr, 10> v;
bool attr_diagnosed = false;
int first_attr = -1;
+ int pack = -1;
unsigned int cnt = 0;
if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE))
while (true)
{
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ location_t elloc = cp_lexer_peek_token (parser->lexer)->location;
+ if (!processing_template_decl)
+ error_at (elloc, "structured binding pack outside of template");
+ else if (pack != -1)
+ error_at (elloc,
+ "multiple packs in structured binding declaration");
+ else
+ {
+ if (keyword == RID_MAX
+ && cxx_dialect >= cxx17
+ && cxx_dialect < cxx26)
+ pedwarn (elloc, OPT_Wc__26_extensions,
+ "structured binding packs only available with "
+ "%<-std=c++2c%> or %<-std=gnu++2c%>");
+ pack = cnt;
+ }
+ cp_lexer_consume_token (parser->lexer);
+ }
cp_expr e = cp_parser_identifier (parser);
if (e.get_value () == error_mark_node)
break;
tree attr = NULL_TREE;
if (cp_next_tokens_can_be_std_attribute_p (parser))
{
- if (cxx_dialect >= cxx17 && cxx_dialect < cxx26 && !attr_diagnosed)
+ if (keyword == RID_MAX
+ && cxx_dialect >= cxx17
+ && cxx_dialect < cxx26
+ && !attr_diagnosed)
{
pedwarn (cp_lexer_peek_token (parser->lexer)->location,
OPT_Wc__26_extensions,
@@ -16851,7 +17342,7 @@ cp_parser_decomposition_declaration (cp_parser *parser,
&pushed_scope);
tree orig_decl = decl;
- unsigned int i;
+ unsigned int i, j;
cp_expr e;
cp_decl_specifier_seq decl_specs;
clear_decl_specs (&decl_specs);
@@ -16859,6 +17350,7 @@ cp_parser_decomposition_declaration (cp_parser *parser,
if (decl_specifiers->storage_class == sc_static)
decl_specs.storage_class = sc_static;
tree prev = decl;
+ j = 0;
FOR_EACH_VEC_ELT (v, i, e)
{
if (i == 0)
@@ -16887,11 +17379,29 @@ cp_parser_decomposition_declaration (cp_parser *parser,
else
{
prev = decl2;
- DECL_DECLARED_CONSTEXPR_P (decl2) = DECL_DECLARED_CONSTEXPR_P (decl);
- DECL_DECLARED_CONSTINIT_P (decl2) = DECL_DECLARED_CONSTINIT_P (decl);
+ if (decl != error_mark_node)
+ {
+ DECL_DECLARED_CONSTEXPR_P (decl2)
+ = DECL_DECLARED_CONSTEXPR_P (decl);
+ DECL_DECLARED_CONSTINIT_P (decl2)
+ = DECL_DECLARED_CONSTINIT_P (decl);
+ }
+ if (j == (unsigned) pack)
+ {
+ tree dtype = cxx_make_type (DECLTYPE_TYPE);
+ DECLTYPE_TYPE_EXPR (dtype) = decl2;
+ DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1;
+ SET_TYPE_STRUCTURAL_EQUALITY (dtype);
+ tree type = cxx_make_type (TYPE_PACK_EXPANSION);
+ PACK_EXPANSION_PATTERN (type) = dtype;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+ PACK_EXPANSION_PARAMETER_PACKS (type) = decl2;
+ TREE_TYPE (decl2) = type;
+ }
}
if (elt_pushed_scope)
pop_scope (elt_pushed_scope);
+ ++j;
}
if (v.is_empty ())
@@ -17695,9 +18205,7 @@ cp_parser_static_assert (cp_parser *parser, bool member_p)
"only available with %<-std=c++17%> or %<-std=gnu++17%>");
/* Eat the ')' */
cp_lexer_consume_token (parser->lexer);
- message = build_string (1, "");
- TREE_TYPE (message) = char_array_type_node;
- fix_string_type (message);
+ message = build_empty_string ();
}
else
{
@@ -27008,6 +27516,10 @@ cp_parser_braced_list (cp_parser *parser, bool *non_constant_p /*=nullptr*/)
location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
auto oas = make_temp_override (parser->omp_array_section_p, false);
+ /* Within a brace-enclosed initializer list, a `>' token is always the
+ greater-than operator. */
+ auto gto = make_temp_override (parser->greater_than_is_operator_p, true);
+
/* Consume the `{' token. */
matching_braces braces;
bool found_opening_brace = braces.require_open (parser);
@@ -28827,12 +29339,20 @@ cp_parser_member_specification_opt (cp_parser* parser)
/* Parse a member-declaration.
member-declaration:
- decl-specifier-seq [opt] member-declarator-list [opt] ;
- function-definition ; [opt]
- :: [opt] nested-name-specifier template [opt] unqualified-id ;
+ attribute-specifier-seq [opt] decl-specifier-seq [opt]
+ member-declarator-list [opt] ;
+ function-definition
+ friend-type-declaration
using-declaration
+ using-enum-declaration
+ static_assert-declaration
+ consteval-block-declaration
template-declaration
+ explicit-specialization
+ deduction-guide
alias-declaration
+ opaque-enum-declaration
+ empty-declaration
member-declarator-list:
member-declarator
@@ -28851,12 +29371,7 @@ cp_parser_member_specification_opt (cp_parser* parser)
member-declarator:
declarator attributes [opt] pure-specifier [opt]
declarator attributes [opt] constant-initializer [opt]
- identifier [opt] attributes [opt] : constant-expression
-
- C++0x Extensions:
-
- member-declaration:
- static_assert-declaration */
+ identifier [opt] attributes [opt] : constant-expression */
static void
cp_parser_member_declaration (cp_parser* parser)
@@ -28869,16 +29384,17 @@ cp_parser_member_declaration (cp_parser* parser)
cp_token *token = NULL;
cp_token *decl_spec_token_start = NULL;
cp_token *initializer_token_start = NULL;
- int saved_pedantic;
+ int saved_pedantic, saved_long_long;
bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
/* Check for the `__extension__' keyword. */
- if (cp_parser_extension_opt (parser, &saved_pedantic))
+ if (cp_parser_extension_opt (parser, &saved_pedantic, &saved_long_long))
{
/* Recurse. */
cp_parser_member_declaration (parser);
/* Restore the old value of the PEDANTIC flag. */
pedantic = saved_pedantic;
+ warn_long_long = saved_long_long;
return;
}
@@ -28955,6 +29471,12 @@ cp_parser_member_declaration (cp_parser* parser)
return;
}
+ if (cp_parser_next_tokens_are_consteval_block_p (parser))
+ {
+ cp_parser_consteval_block (parser, /*member_p=*/true);
+ return;
+ }
+
parser->colon_corrects_to_scope_p = false;
cp_omp_declare_simd_data odsd;
@@ -32020,13 +32542,16 @@ cp_parser_skip_attributes_opt (cp_parser *parser, size_t n)
present, and FALSE otherwise. *SAVED_PEDANTIC is set to the
current value of the PEDANTIC flag, regardless of whether or not
the `__extension__' keyword is present. The caller is responsible
- for restoring the value of the PEDANTIC flag. */
+ for restoring the value of the PEDANTIC flag. Similarly *SAVED_LONG_LONG
+ for warn_long_long flag. */
static bool
-cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic)
+cp_parser_extension_opt (cp_parser *parser, int *saved_pedantic,
+ int *saved_long_long)
{
/* Save the old value of the PEDANTIC flag. */
*saved_pedantic = pedantic;
+ *saved_long_long = warn_long_long;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTENSION))
{
@@ -32035,6 +32560,8 @@ cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic)
/* We're not being pedantic while the `__extension__' keyword is
in effect. */
pedantic = 0;
+ /* And we don't want -Wlong-long warning. */
+ warn_long_long = 0;
return true;
}
@@ -32882,9 +33409,12 @@ cp_parser_compound_requirement (cp_parser *parser)
}
}
else
- /* P1452R2 removed the trailing-return-type option. */
- error_at (type_loc,
- "return-type-requirement is not a type-constraint");
+ {
+ /* P1452R2 removed the trailing-return-type option. */
+ error_at (type_loc,
+ "return-type-requirement is not a type-constraint");
+ type = NULL_TREE;
+ }
}
location_t loc = make_location (expr_token->location,
@@ -36653,7 +37183,11 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
case CPP_CLOSE_SQUARE:
if (depth == 0
/* Handle correctly int n = sizeof ... ( p ); */
- && token->type != CPP_ELLIPSIS)
+ && (token->type != CPP_ELLIPSIS
+ /* For int n = 42 ...) handle ... as variadic arguments. */
+ || (!nsdmi
+ && cp_lexer_nth_token_is (parser->lexer, 2,
+ CPP_CLOSE_PAREN))))
done = true;
/* Update DEPTH, if necessary. */
else if (token->type == CPP_CLOSE_PAREN
@@ -42543,8 +43077,11 @@ cp_parser_omp_clause_doacross (cp_parser *parser, tree list, location_t loc)
to ( variable-list )
OpenMP 5.1:
- from ( [present :] variable-list )
- to ( [present :] variable-list ) */
+ from ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list )
+ to ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list )
+
+ motion-modifier:
+ present | iterator (iterators-definition) */
static tree
cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind,
@@ -42553,23 +43090,113 @@ cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind,
if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return list;
- bool present = false;
- cp_token *token = cp_lexer_peek_token (parser->lexer);
+ int pos = 1;
+ int colon_pos = 0;
+ int iterator_length = 0;
- if (token->type == CPP_NAME
- && strcmp (IDENTIFIER_POINTER (token->u.value), "present") == 0
- && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON))
+ while (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_NAME)
{
- present = true;
- cp_lexer_consume_token (parser->lexer);
- cp_lexer_consume_token (parser->lexer);
+ const char *identifier =
+ IDENTIFIER_POINTER (cp_lexer_peek_nth_token (parser->lexer,
+ pos)->u.value);
+ if (cp_lexer_nth_token_is (parser->lexer, pos + 1, CPP_OPEN_PAREN))
+ {
+ int n = cp_parser_skip_balanced_tokens (parser, pos + 1);
+ if (n != pos + 1)
+ {
+ if (strcmp (identifier, "iterator") == 0)
+ iterator_length = n - pos;
+ pos = n - 1;
+ }
+ }
+ if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA)
+ pos += 2;
+ else
+ pos++;
+ if (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_COLON)
+ {
+ colon_pos = pos;
+ break;
+ }
}
+ bool present = false;
+ tree iterators = NULL_TREE;
+
+ for (int pos = 1; pos < colon_pos; ++pos)
+ {
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ if (token->type == CPP_COMMA)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ continue;
+ }
+ const char *p = IDENTIFIER_POINTER (token->u.value);
+ if (strcmp ("present", p) == 0)
+ {
+ if (present)
+ {
+ cp_parser_error (parser, "too many %<present%> modifiers");
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
+ present = true;
+ cp_lexer_consume_token (parser->lexer);
+ }
+ else if (strcmp ("iterator", p) == 0)
+ {
+ if (iterators)
+ {
+ cp_parser_error (parser, "too many %<iterator%> modifiers");
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
+ begin_scope (sk_omp, NULL);
+ iterators = cp_parser_omp_iterators (parser);
+ pos += iterator_length - 1;
+ }
+
+ else
+ {
+ error_at (token->location,
+ "%qs clause with modifier other than %<iterator%> "
+ "or %<present%>",
+ kind == OMP_CLAUSE_TO ? "to" : "from");
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
+ }
+
+ if (colon_pos)
+ cp_parser_require (parser, CPP_COLON, RT_COLON);
+
tree nl = cp_parser_omp_var_list_no_open (parser, kind, list, NULL, true);
if (present)
for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
OMP_CLAUSE_MOTION_PRESENT (c) = 1;
+ if (iterators)
+ {
+ tree block = poplevel (1, 1, 0);
+ if (iterators == error_mark_node)
+ iterators = NULL_TREE;
+ else
+ TREE_VEC_ELT (iterators, 5) = block;
+ }
+
+ if (iterators)
+ for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_ITERATORS (c) = iterators;
+
return nl;
}
@@ -42603,16 +43230,34 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p)
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)
+ int iterator_length = 0;
+ for (;;)
{
- if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COLON)
+ cp_token *tok = cp_lexer_peek_nth_token (parser->lexer, pos);
+ if (!(tok->type == CPP_NAME || tok->keyword == RID_DELETE))
+ break;
+
+ cp_token *next_tok = cp_lexer_peek_nth_token (parser->lexer, pos + 1);
+ if (tok->type == CPP_NAME
+ && strcmp (IDENTIFIER_POINTER (tok->u.value), "iterator") == 0
+ && next_tok->type == CPP_OPEN_PAREN)
+ {
+ int n = cp_parser_skip_balanced_tokens (parser, pos + 1);
+ if (n != pos + 1)
+ {
+ iterator_length = n - pos;
+ pos = n - 1;
+ next_tok = cp_lexer_peek_nth_token (parser->lexer, n);
+ }
+ }
+
+ if (next_tok->type == CPP_COLON)
{
map_kind_pos = pos;
break;
}
- if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA)
+ if (next_tok->type == CPP_COMMA)
pos++;
else if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type
== CPP_OPEN_PAREN)
@@ -42625,6 +43270,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p)
bool present_modifier = false;
bool mapper_modifier = false;
tree mapper_name = NULL_TREE;
+ tree iterators = NULL_TREE;
for (int pos = 1; pos < map_kind_pos; ++pos)
{
cp_token *tok = cp_lexer_peek_token (parser->lexer);
@@ -42663,6 +43309,21 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p)
close_modifier = true;
cp_lexer_consume_token (parser->lexer);
}
+ else if (strcmp ("iterator", p) == 0)
+ {
+ if (iterators)
+ {
+ cp_parser_error (parser, "too many %<iterator%> modifiers");
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ return list;
+ }
+ begin_scope (sk_omp, NULL);
+ iterators = cp_parser_omp_iterators (parser);
+ pos += iterator_length - 1;
+ }
else if (strcmp ("mapper", p) == 0)
{
cp_lexer_consume_token (parser->lexer);
@@ -42751,7 +43412,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p)
{
cp_parser_error (parser, "%<map%> clause with map-type modifier "
"other than %<always%>, %<close%>, "
- "%<mapper%> or %<present%>");
+ "%<iterator%>, %<mapper%> or %<present%>");
cp_parser_skip_to_closing_parenthesis (parser,
/*recovering=*/true,
/*or_comma=*/false,
@@ -42815,9 +43476,19 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p)
tree last_new = NULL_TREE;
+ 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_SET_MAP_KIND (c, kind);
+ OMP_CLAUSE_ITERATORS (c) = iterators;
last_new = c;
}
@@ -46070,8 +46741,16 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl,
decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
decomp->decl = decl;
}
+ else if (TREE_CODE (v) == TREE_VEC
+ && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0)))
+ {
+ d = TREE_VEC_ELT (v, 0);
+ decomp = &decomp_d;
+ decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1;
+ decomp->decl = decl;
+ }
}
- do_range_for_auto_deduction (d, init, decomp);
+ do_range_for_auto_deduction (d, init, decomp, false);
}
cond = global_namespace;
incr = NULL_TREE;
@@ -46127,8 +46806,8 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl,
range_temp_decl = range_temp;
range_temp = convert_from_reference (range_temp);
}
- iter_type = cp_parser_perform_range_for_lookup (range_temp,
- &begin_expr, &end_expr);
+ iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr,
+ &end_expr);
}
tree end_iter_type = iter_type;
@@ -46193,6 +46872,15 @@ cp_convert_omp_range_for (tree &this_pre_body, tree &sl,
decomp->count = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
decomp->decl = d;
}
+ else if (TREE_CODE (v) == TREE_VEC
+ && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0)))
+ {
+ tree d = orig_decl;
+ orig_decl = TREE_VEC_ELT (v, 0);
+ decomp = &decomp_d;
+ decomp->count = tree_to_uhwi (TREE_VEC_ELT (v, 1)) + 1;
+ decomp->decl = d;
+ }
}
tree auto_node = type_uses_auto (TREE_TYPE (orig_decl));
@@ -50956,41 +51644,41 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
append_args_tree);
}
} while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL));
+ if (variant != error_mark_node && !has_match)
+ {
+ cp_parser_error (parser, "expected %<match%> clause");
+ variant = error_mark_node;
+ }
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
- if ((ctx != error_mark_node && variant != error_mark_node)
- && (has_adjust_args || append_args_tree))
+ /* At this point, we have completed parsing of the pragma, now it's
+ on to error checking. */
+ if (variant == error_mark_node || ctx == error_mark_node)
+ /* Previously diagnosed error. */
+ return attrs;
+
+ if (has_adjust_args || append_args_tree)
{
- if (!has_match)
+ if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
+ OMP_TRAIT_CONSTRUCT_DISPATCH))
{
error_at (has_adjust_args ? adjust_args_loc : append_args_loc,
- "an %qs clause requires a %<match%> clause",
+ "an %qs clause can only be specified if the %<dispatch%> "
+ "selector of the construct selector set appears "
+ "in the %<match%> clause",
has_adjust_args ? "adjust_args" : "append_args");
+ return attrs;
}
- else
- {
- gcc_assert (TREE_PURPOSE (attrs)
- == get_identifier ("omp declare variant base"));
- gcc_assert (TREE_PURPOSE (TREE_VALUE (attrs)) == variant);
- ctx = TREE_VALUE (TREE_VALUE (attrs));
- if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
- OMP_TRAIT_CONSTRUCT_DISPATCH))
- error_at (has_adjust_args ? adjust_args_loc : append_args_loc,
- "an %qs clause can only be specified if the %<dispatch%> "
- "selector of the construct selector set appears "
- "in the %<match%> clause",
- has_adjust_args ? "adjust_args" : "append_args");
- // We might not have a DECL for the variant yet. So we store the
- // need_device_ptr list in the base function attribute, after loc
- // nodes.
- tree t = build_tree_list (need_device_ptr_list,
- NULL_TREE /* need_device_addr */);
- TREE_CHAIN (t) = append_args_tree;
- TREE_VALUE (attrs) = chainon (TREE_VALUE (attrs),
- build_tree_list ( NULL_TREE, t));
- }
+ // We might not have a DECL for the variant yet. So we store the
+ // need_device_ptr list in the base function attribute, after loc
+ // nodes.
+ tree t = build_tree_list (need_device_ptr_list,
+ NULL_TREE /* need_device_addr */);
+ TREE_CHAIN (t) = append_args_tree;
+ TREE_VALUE (attrs) = chainon (TREE_VALUE (attrs),
+ build_tree_list (NULL_TREE, t));
}
- cp_parser_skip_to_pragma_eol (parser, pragma_tok);
return attrs;
}
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index f9ed801..3a17be9 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -328,14 +328,16 @@ struct GTY(()) cp_parser {
/* Set to IN_ITERATION_STMT if parsing an iteration-statement,
to IN_OMP_BLOCK if parsing OpenMP structured block and
- IN_OMP_FOR if parsing OpenMP loop. If parsing a switch statement,
+ IN_OMP_FOR if parsing OpenMP loop, IN_EXPANSION_STMT if parsing an
+ expansion-statement. If parsing a switch statement,
this is bitwise ORed with IN_SWITCH_STMT, unless parsing an
iteration-statement, OpenMP block or loop within that switch. */
#define IN_SWITCH_STMT 1
#define IN_ITERATION_STMT 2
#define IN_OMP_BLOCK 4
#define IN_OMP_FOR 8
-#define IN_IF_STMT 16
+#define IN_IF_STMT 16
+#define IN_EXPANSION_STMT 32
unsigned char in_statement;
/* TRUE if we are presently parsing the body of a switch statement.
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 71ae764..65de1cf 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see
#include "builtins.h"
#include "omp-general.h"
#include "pretty-print-markup.h"
+#include "contracts.h"
/* The type of functions taking a tree, and some additional data, and
returning an int. */
@@ -6952,14 +6953,22 @@ convert_nontype_argument_function (tree type, tree expr,
{
auto_diagnostic_group d;
location_t loc = cp_expr_loc_or_input_loc (expr);
- error_at (loc, "%qE is not a valid template argument for type %qT",
- expr, type);
- if (TYPE_PTR_P (type))
- inform (loc, "it must be the address of a function "
- "with external linkage");
+ tree c;
+ if (cxx_dialect >= cxx17
+ && (c = cxx_constant_value (fn),
+ c == error_mark_node))
+ ;
else
- inform (loc, "it must be the name of a function with "
- "external linkage");
+ {
+ error_at (loc, "%qE is not a valid template argument for "
+ "type %qT", expr, type);
+ if (TYPE_PTR_P (type))
+ inform (loc, "it must be the address of a function "
+ "with external linkage");
+ else
+ inform (loc, "it must be the name of a function with "
+ "external linkage");
+ }
}
return NULL_TREE;
}
@@ -7402,22 +7411,22 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
/* Null pointer values are OK in C++11. */;
else
{
- if (VAR_P (expr))
- {
- if (complain & tf_error)
- error ("%qD is not a valid template argument "
- "because %qD is a variable, not the address of "
- "a variable", expr, expr);
- return true;
- }
+ tree c;
+ if (!(complain & tf_error))
+ ;
+ else if (cxx_dialect >= cxx17
+ && (c = cxx_constant_value (expr),
+ c == error_mark_node))
+ ;
+ else if (VAR_P (expr))
+ error ("%qD is not a valid template argument "
+ "because %qD is a variable, not the address of "
+ "a variable", expr, expr);
else
- {
- if (complain & tf_error)
- error ("%qE is not a valid template argument for %qT "
- "because it is not the address of a variable",
- expr, type);
- return true;
- }
+ error ("%qE is not a valid template argument for %qT "
+ "because it is not the address of a variable",
+ expr, type);
+ return true;
}
}
return false;
@@ -11445,7 +11454,8 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc)
#pragma GCC diagnostic ignored "-Wformat-diag"
#endif
bool list_p = new_level->list_p ();
- if (list_p && !pp.has_flag (TDF_DETAILS))
+ if ((list_p || TREE_CODE (tldcl) == TEMPLATE_FOR_STMT)
+ && !pp.has_flag (TDF_DETAILS))
/* Skip non-instantiations unless -details. */;
else
{
@@ -11461,7 +11471,9 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc)
}
for (int i = 0; i < tinst_depth; ++i)
pp_space (&pp);
- if (list_p)
+ if (TREE_CODE (tldcl) == TEMPLATE_FOR_STMT)
+ pp_printf (&pp, "I template for");
+ else if (list_p)
pp_printf (&pp, "S %S", new_level->get_node ());
else
pp_printf (&pp, "I %D", tldcl);
@@ -11575,7 +11587,9 @@ reopen_tinst_level (struct tinst_level *level)
{
last_ctx = ctx;
pp_newline (&pp);
- if (t->list_p ())
+ if (TREE_CODE (t->tldcl) == TEMPLATE_FOR_STMT)
+ pp_printf (&pp, "RI template for");
+ else if (t->list_p ())
pp_printf (&pp, "RS %S", ctx);
else
pp_printf (&pp, "RI %D", ctx);
@@ -13973,9 +13987,30 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
else if (is_capture_proxy (parm_pack))
{
arg_pack = retrieve_local_specialization (parm_pack);
+ if (DECL_DECOMPOSITION_P (arg_pack))
+ {
+ orig_arg = arg_pack;
+ goto expand_sb_pack;
+ }
if (DECL_PACK_P (arg_pack))
arg_pack = NULL_TREE;
}
+ else if (DECL_DECOMPOSITION_P (parm_pack))
+ {
+ orig_arg = retrieve_local_specialization (parm_pack);
+ expand_sb_pack:
+ gcc_assert (DECL_DECOMPOSITION_P (orig_arg));
+ if (TREE_TYPE (orig_arg) == error_mark_node)
+ return error_mark_node;
+ gcc_assert (DECL_HAS_VALUE_EXPR_P (orig_arg));
+ arg_pack = DECL_VALUE_EXPR (orig_arg);
+ tree vec = make_tree_vec (TREE_VEC_LENGTH (arg_pack) - 2);
+ if (TREE_VEC_LENGTH (vec))
+ memcpy (TREE_VEC_BEGIN (vec), &TREE_VEC_ELT (arg_pack, 2),
+ TREE_VEC_LENGTH (vec) * sizeof (tree));
+ arg_pack = make_node (NONTYPE_ARGUMENT_PACK);
+ ARGUMENT_PACK_ARGS (arg_pack) = vec;
+ }
else
{
int idx;
@@ -13988,7 +14023,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
arg_pack = NULL_TREE;
}
- orig_arg = arg_pack;
+ if (orig_arg == NULL_TREE)
+ orig_arg = arg_pack;
if (arg_pack && TREE_CODE (arg_pack) == ARGUMENT_PACK_SELECT)
arg_pack = ARGUMENT_PACK_SELECT_FROM_PACK (arg_pack);
@@ -14003,8 +14039,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
if (arg_pack)
{
- int my_len =
- TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack));
+ int my_len
+ = TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack));
/* Don't bother trying to do a partial substitution with
incomplete packs; we'll try again after deduction. */
@@ -14168,8 +14204,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
/* Update the corresponding argument. */
if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
- TREE_VEC_ELT (TREE_VEC_ELT (args, level -1 ), idx) =
- TREE_TYPE (pack);
+ TREE_VEC_ELT (TREE_VEC_ELT (args, level -1 ), idx)
+ = TREE_TYPE (pack);
else
TREE_VEC_ELT (args, idx) = TREE_TYPE (pack);
}
@@ -15913,7 +15949,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
tsubst_flags_t tcomplain = complain;
if (VAR_P (t))
tcomplain |= tf_tst_ok;
- type = tsubst (type, args, tcomplain, in_decl);
+ if (DECL_DECOMPOSITION_P (t) && DECL_PACK_P (t))
+ type = NULL_TREE;
+ else
+ type = tsubst (type, args, tcomplain, in_decl);
/* Substituting the type might have recursively instantiated this
same alias (c++/86171). */
if (use_spec_table && gen_tmpl && DECL_ALIAS_TEMPLATE_P (gen_tmpl)
@@ -15930,6 +15969,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,
{
DECL_INITIALIZED_P (r) = 0;
DECL_TEMPLATE_INSTANTIATED (r) = 0;
+ if (DECL_DECOMPOSITION_P (t) && DECL_PACK_P (t))
+ {
+ tree dtype = cxx_make_type (DECLTYPE_TYPE);
+ DECLTYPE_TYPE_EXPR (dtype) = r;
+ DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1;
+ SET_TYPE_STRUCTURAL_EQUALITY (dtype);
+ type = cxx_make_type (TYPE_PACK_EXPANSION);
+ PACK_EXPANSION_PATTERN (type) = dtype;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+ PACK_EXPANSION_PARAMETER_PACKS (type) = r;
+ }
if (TREE_CODE (type) == FUNCTION_TYPE)
{
/* It may seem that this case cannot occur, since:
@@ -18547,13 +18597,17 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv,
if (decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (decl))
{
tree v = DECL_VALUE_EXPR (decl);
- if (TREE_CODE (v) == ARRAY_REF
- && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+ if ((TREE_CODE (v) == ARRAY_REF
+ && DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
+ || (TREE_CODE (v) == TREE_VEC
+ && DECL_DECOMPOSITION_P (TREE_VEC_ELT (v, 0))))
{
+ v = (TREE_CODE (v) == ARRAY_REF
+ ? TREE_OPERAND (v, 0) : TREE_VEC_ELT (v, 0));
cp_decomp decomp_d = { NULL_TREE, 0 };
- tree d = tsubst_decl (TREE_OPERAND (v, 0), args, complain);
+ tree d = tsubst_decl (v, args, complain);
maybe_push_decl (d);
- d = tsubst_decomp_names (d, TREE_OPERAND (v, 0), args, complain,
+ d = tsubst_decomp_names (d, v, args, complain,
in_decl, &decomp_d);
decomp = true;
if (d == error_mark_node)
@@ -19330,6 +19384,62 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
finish_do_stmt (tmp, stmt, false, 0, false);
break;
+ case TEMPLATE_FOR_STMT:
+ {
+ tree init;
+ stmt = build_stmt (EXPR_LOCATION (t), TEMPLATE_FOR_STMT, NULL_TREE,
+ NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
+ TEMPLATE_FOR_SCOPE (stmt) = begin_template_for_scope (&init);
+ TEMPLATE_FOR_INIT_STMT (stmt) = init;
+ RECUR (TEMPLATE_FOR_INIT_STMT (t));
+ TEMPLATE_FOR_EXPR (stmt) = RECUR (TEMPLATE_FOR_EXPR (t));
+ if (processing_template_decl)
+ {
+ tree orig_decl = TEMPLATE_FOR_DECL (t);
+ if (TREE_CODE (orig_decl) == TREE_VEC)
+ orig_decl = TREE_VEC_ELT (orig_decl, 0);
+ tree decl = tsubst (orig_decl, args, complain, in_decl);
+ maybe_push_decl (decl);
+
+ cp_decomp decomp_d, *decomp = NULL;
+ if (DECL_DECOMPOSITION_P (decl))
+ {
+ decomp = &decomp_d;
+ decl = tsubst_decomp_names (decl, orig_decl, args,
+ complain, in_decl, decomp);
+ if (decl != error_mark_node)
+ {
+ tree v = make_tree_vec (decomp->count + 1);
+ TREE_VEC_ELT (v, 0) = decl;
+ decl = decomp->decl;
+ for (unsigned i = 0; i < decomp->count; ++i)
+ {
+ TREE_VEC_ELT (v, decomp->count - i) = decl;
+ decl = DECL_CHAIN (decl);
+ }
+ decl = v;
+ }
+ }
+ TEMPLATE_FOR_DECL (stmt) = decl;
+ TEMPLATE_FOR_INIT_STMT (stmt) = pop_stmt_list (init);
+ add_stmt (stmt);
+ TEMPLATE_FOR_BODY (stmt) = do_pushlevel (sk_block);
+ bool prev = note_iteration_stmt_body_start ();
+ RECUR (TEMPLATE_FOR_BODY (t));
+ note_iteration_stmt_body_end (prev);
+ TEMPLATE_FOR_BODY (stmt)
+ = do_poplevel (TEMPLATE_FOR_BODY (stmt));
+ }
+ else
+ {
+ TEMPLATE_FOR_DECL (stmt) = TEMPLATE_FOR_DECL (t);
+ TEMPLATE_FOR_BODY (stmt) = TEMPLATE_FOR_BODY (t);
+ finish_expansion_stmt (stmt, args, complain, in_decl);
+ }
+ add_stmt (do_poplevel (TEMPLATE_FOR_SCOPE (stmt)));
+ }
+ break;
+
case IF_STMT:
stmt = begin_if_stmt ();
IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t);
@@ -19593,7 +19703,8 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
finish_static_assert (condition, message,
STATIC_ASSERT_SOURCE_LOCATION (t),
- /*member_p=*/false, /*show_expr_p=*/true);
+ /*member_p=*/false, /*show_expr_p=*/true,
+ CONSTEVAL_BLOCK_P (t));
}
break;
@@ -20480,6 +20591,18 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
tree fntype = static_fn_type (oldfn);
+ begin_scope (sk_lambda, NULL_TREE);
+
+ /* Like in cp_parser_lambda_expression, we need to bring the captures
+ into the lambda scope. */
+ tree ns = decl_namespace_context (type);
+ push_nested_namespace (ns);
+ push_nested_class (type);
+ tree dummy_fco = maybe_add_dummy_lambda_op (r);
+ pop_nested_class ();
+ pop_nested_namespace (ns);
+ push_capture_proxies (r, /*early_p=*/true);
+
tree saved_ctp = current_template_parms;
if (oldtmpl)
{
@@ -20493,6 +20616,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
--processing_template_decl;
}
+ /* We are about to create the real operator(), so get rid of the old one. */
+ if (dummy_fco)
+ remove_dummy_lambda_op (dummy_fco, r);
+
if (fntype == error_mark_node)
r = error_mark_node;
else
@@ -20526,6 +20653,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
enclosing expression. */
cp_evaluated ev;
+ /* Now we're done with the parameter-declaration-clause, and should
+ assume "const" unless "mutable" was present. */
+ LAMBDA_EXPR_CONST_QUAL_P (r) = LAMBDA_EXPR_CONST_QUAL_P (t);
+
bool nested = cfun;
if (nested)
push_function_context ();
@@ -20594,6 +20725,7 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
}
out:
+ pop_bindings_and_leave_scope ();
finish_struct (type, /*attr*/NULL_TREE);
insert_pending_capture_proxies ();
@@ -21211,7 +21343,28 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
++c_inhibit_evaluation_warnings;
/* We only want to compute the number of arguments. */
if (PACK_EXPANSION_P (op))
- expanded = tsubst_pack_expansion (op, args, complain, in_decl);
+ {
+ expanded = NULL_TREE;
+ if (DECL_DECOMPOSITION_P (PACK_EXPANSION_PATTERN (op)))
+ {
+ tree d = PACK_EXPANSION_PATTERN (op);
+ if (DECL_HAS_VALUE_EXPR_P (d))
+ {
+ d = DECL_VALUE_EXPR (d);
+ if (TREE_CODE (d) == TREE_VEC)
+ {
+ tree b = TREE_VEC_ELT (d, 0);
+ if (!type_dependent_expression_p_push (b))
+ {
+ expanded = void_node;
+ len = TREE_VEC_LENGTH (d) - 2;
+ }
+ }
+ }
+ }
+ if (!expanded)
+ expanded = tsubst_pack_expansion (op, args, complain, in_decl);
+ }
else
expanded = tsubst_template_args (ARGUMENT_PACK_ARGS (op),
args, complain, in_decl);
@@ -22169,6 +22322,11 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (DECL_NAME (t) == this_identifier && current_class_ptr)
RETURN (current_class_ptr);
+ /* Parameters of non-templates map to themselves (e.g. in
+ expansion statement body). */
+ if (DECL_CONTEXT (t) && !uses_template_parms (DECL_CONTEXT (t)))
+ RETURN (t);
+
/* This can happen for a parameter name used later in a function
declaration (such as in a late-specified return type). Just
make a dummy decl, since it's only used for its type. */
@@ -22385,12 +22543,16 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case OFFSET_REF:
{
- tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ /* We should only get here for an OFFSET_REF like A::m; a .* in a
+ template is represented as a DOTSTAR_EXPR. */
+ gcc_checking_assert
+ (same_type_p (TREE_TYPE (t), TREE_TYPE (TREE_OPERAND (t, 1))));
tree op0 = RECUR (TREE_OPERAND (t, 0));
tree op1 = RECUR (TREE_OPERAND (t, 1));
+ tree type = TREE_TYPE (op1);
r = build2 (OFFSET_REF, type, op0, op1);
PTRMEM_OK_P (r) = PTRMEM_OK_P (t);
- if (!mark_used (TREE_OPERAND (r, 1), complain)
+ if (!mark_used (op1, complain)
&& !(complain & tf_error))
RETURN (error_mark_node);
RETURN (r);
@@ -22503,6 +22665,13 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
type1 = tsubst_expr (type1, args, complain, in_decl);
tree type2 = tsubst (TRAIT_EXPR_TYPE2 (t), args,
complain, in_decl);
+ if (TRAIT_EXPR_KIND (t) == CPTK_STRUCTURED_BINDING_SIZE
+ && type1 != error_mark_node
+ && !processing_template_decl)
+ /* __builtin_structured_binding_size handled separately
+ to make it SFINAE friendly. */
+ RETURN (finish_structured_binding_size (TRAIT_EXPR_LOCATION (t),
+ type1, complain));
RETURN (finish_trait_expr (TRAIT_EXPR_LOCATION (t),
TRAIT_EXPR_KIND (t), type1, type2));
}
@@ -29041,6 +29210,24 @@ value_dependent_expression_p (tree expression)
case SIZEOF_EXPR:
if (SIZEOF_EXPR_TYPE_P (expression))
return dependent_type_p (TREE_TYPE (TREE_OPERAND (expression, 0)));
+ if (tree p = TREE_OPERAND (expression, 0))
+ if (PACK_EXPANSION_P (p)
+ && DECL_DECOMPOSITION_P (PACK_EXPANSION_PATTERN (p)))
+ {
+ tree d = PACK_EXPANSION_PATTERN (p);
+ if (DECL_HAS_VALUE_EXPR_P (d))
+ {
+ d = DECL_VALUE_EXPR (d);
+ /* [temp.dep.constexpr]/4:
+ Expressions of the following form are value-dependent:
+ sizeof ... ( identifier )
+ unless the identifier is a structured binding pack whose
+ initializer is not dependent. */
+ if (TREE_CODE (d) == TREE_VEC
+ && !type_dependent_expression_p (TREE_VEC_ELT (d, 0)))
+ return false;
+ }
+ }
/* FALLTHRU */
case ALIGNOF_EXPR:
case TYPEID_EXPR:
@@ -29554,6 +29741,22 @@ instantiation_dependent_r (tree *tp, int *walk_subtrees,
tree op = TREE_OPERAND (*tp, 0);
if (code == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (*tp))
op = TREE_TYPE (op);
+ else if (code == SIZEOF_EXPR
+ && PACK_EXPANSION_P (op)
+ && DECL_DECOMPOSITION_P (PACK_EXPANSION_PATTERN (op)))
+ {
+ tree d = PACK_EXPANSION_PATTERN (op);
+ if (DECL_HAS_VALUE_EXPR_P (d))
+ {
+ d = DECL_VALUE_EXPR (d);
+ if (TREE_CODE (d) == TREE_VEC
+ && !type_dependent_expression_p (TREE_VEC_ELT (d, 0)))
+ {
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
+ }
+ }
if (TYPE_P (op))
{
if (dependent_type_p (op))
@@ -32448,6 +32651,401 @@ add_mergeable_specialization (bool decl_p, spec_entry *elt, tree decl,
}
}
+struct expansion_stmt_bc
+{
+ tree break_label;
+ tree continue_label;
+ hash_set<tree> *pset;
+ location_t loc;
+ bool in_switch;
+};
+
+/* Helper function for finish_expansion_stmt. Find BREAK_STMT (not
+ nested inside of other WHILE_STMT, FOR_STMT, DO_STMT, TEMPLATE_FOR_STMT
+ or SWITCH_STMT) or CONTINUE_STMT (not nested inside those except
+ perhaps SWITCH_STMT) and replace them with GOTO_EXPR to lazily created
+ label. */
+
+static tree
+expansion_stmt_find_bc_r (tree *tp, int *walk_subtrees, void *data)
+{
+ tree t = *tp;
+ expansion_stmt_bc *bc_data = (expansion_stmt_bc *) data;
+ switch (TREE_CODE (t))
+ {
+ case WHILE_STMT:
+ *walk_subtrees = 0;
+ for (int i = 0; i < TREE_CODE_LENGTH (WHILE_STMT); ++i)
+ if (&TREE_OPERAND (t, i) != &WHILE_BODY (t))
+ cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ break;
+ case FOR_STMT:
+ *walk_subtrees = 0;
+ for (int i = 0; i < TREE_CODE_LENGTH (FOR_STMT); ++i)
+ if (&TREE_OPERAND (t, i) != &FOR_BODY (t))
+ cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ break;
+ case DO_STMT:
+ *walk_subtrees = 0;
+ for (int i = 0; i < TREE_CODE_LENGTH (DO_STMT); ++i)
+ if (&TREE_OPERAND (t, i) != &DO_BODY (t))
+ cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ break;
+ case TEMPLATE_FOR_STMT:
+ *walk_subtrees = 0;
+ for (int i = 0; i < TREE_CODE_LENGTH (TEMPLATE_FOR_STMT); ++i)
+ if (&TREE_OPERAND (t, i) != &TEMPLATE_FOR_BODY (t))
+ cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ break;
+ case SWITCH_STMT:
+ if (!bc_data->in_switch)
+ {
+ *walk_subtrees = 0;
+ for (int i = 0; i < TREE_CODE_LENGTH (SWITCH_STMT); ++i)
+ if (&TREE_OPERAND (t, i) != &SWITCH_STMT_BODY (t))
+ cp_walk_tree (&TREE_OPERAND (t, i), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ bc_data->in_switch = true;
+ cp_walk_tree (&SWITCH_STMT_BODY (t), expansion_stmt_find_bc_r,
+ data, bc_data->pset);
+ bc_data->in_switch = false;
+ }
+ break;
+ case BREAK_STMT:
+ if (!bc_data->in_switch)
+ {
+ if (!bc_data->break_label)
+ {
+ bc_data->break_label = create_artificial_label (bc_data->loc);
+ TREE_USED (bc_data->break_label) = 1;
+ LABEL_DECL_BREAK (bc_data->break_label) = true;
+ }
+ *tp = build1_loc (EXPR_LOCATION (t), GOTO_EXPR, void_type_node,
+ bc_data->break_label);
+ }
+ break;
+ case CONTINUE_STMT:
+ if (!bc_data->continue_label)
+ {
+ bc_data->continue_label = create_artificial_label (bc_data->loc);
+ TREE_USED (bc_data->continue_label) = 1;
+ LABEL_DECL_CONTINUE (bc_data->continue_label) = true;
+ }
+ *tp = build1_loc (EXPR_LOCATION (t), GOTO_EXPR, void_type_node,
+ bc_data->continue_label);
+ break;
+ default:
+ if (TYPE_P (t))
+ *walk_subtrees = 0;
+ break;
+ }
+ return NULL_TREE;
+}
+
+/* Finish an expansion-statement. */
+
+void
+finish_expansion_stmt (tree expansion_stmt, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ tree expansion_init = TEMPLATE_FOR_EXPR (expansion_stmt);
+ if (error_operand_p (expansion_init))
+ return;
+
+ enum expansion_stmt_kind {
+ esk_none,
+ esk_iterating,
+ esk_destructuring,
+ esk_enumerating
+ } kind = esk_none;
+
+ unsigned HOST_WIDE_INT n = 0;
+ tree range_decl = TEMPLATE_FOR_DECL (expansion_stmt);
+ bool is_decomp = false;
+ if (TREE_CODE (range_decl) == TREE_VEC)
+ {
+ is_decomp = true;
+ range_decl = TREE_VEC_ELT (range_decl, 0);
+ }
+ if (error_operand_p (range_decl))
+ return;
+
+ location_t loc = DECL_SOURCE_LOCATION (range_decl);
+ tree begin = NULL_TREE;
+ auto_vec<tree, 8> destruct_decls;
+ if (BRACE_ENCLOSED_INITIALIZER_P (expansion_init))
+ {
+ /* Enumerating expansion statements. */
+ kind = esk_enumerating;
+ n = CONSTRUCTOR_NELTS (expansion_init);
+ }
+ else if (TYPE_REF_P (TREE_TYPE (expansion_init))
+ ? TREE_CODE (TREE_TYPE (TREE_TYPE (expansion_init))) != ARRAY_TYPE
+ : TREE_CODE (TREE_TYPE (expansion_init)) != ARRAY_TYPE)
+ {
+ tree range_temp, begin_expr, end_expr, iter_type;
+ range_temp = convert_from_reference (build_range_temp (expansion_init));
+ iter_type = cp_perform_range_for_lookup (range_temp, &begin_expr,
+ &end_expr, tf_none);
+ if (begin_expr != error_mark_node && end_expr != error_mark_node)
+ {
+ kind = esk_iterating;
+ gcc_assert (iter_type);
+ }
+ }
+ if (kind == esk_iterating)
+ {
+ /* Iterating expansion statements. */
+ tree end;
+ begin = cp_build_range_for_decls (loc, expansion_init, &end, true);
+ if (!error_operand_p (begin) && !error_operand_p (end))
+ {
+ tree i = get_target_expr (begin);
+ tree w = build_stmt (loc, WHILE_STMT, NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE, NULL_TREE);
+ tree r = get_target_expr (build_zero_cst (ptrdiff_type_node));
+ tree iinc = build_x_unary_op (loc, PREINCREMENT_EXPR,
+ TARGET_EXPR_SLOT (i), NULL_TREE,
+ tf_warning_or_error);
+ tree rinc = build2 (PREINCREMENT_EXPR, ptrdiff_type_node,
+ TARGET_EXPR_SLOT (r),
+ build_int_cst (ptrdiff_type_node, 1));
+ WHILE_BODY (w) = build_compound_expr (loc, iinc, rinc);
+ WHILE_COND (w) = build_x_binary_op (loc, NE_EXPR, i, ERROR_MARK,
+ end, ERROR_MARK, NULL_TREE, NULL,
+ tf_warning_or_error);
+ tree e = build_compound_expr (loc, r, i);
+ e = build_compound_expr (loc, e, w);
+ e = build_compound_expr (loc, e, TARGET_EXPR_SLOT (r));
+ e = cxx_constant_value (e);
+ if (tree_fits_uhwi_p (e))
+ n = tree_to_uhwi (e);
+ }
+ }
+ else if (kind == esk_none)
+ {
+ kind = esk_destructuring;
+ HOST_WIDE_INT sz = cp_decomp_size (loc, TREE_TYPE (expansion_init),
+ tf_warning_or_error);
+ if (sz < 0)
+ return;
+ n = sz;
+ tree auto_node = make_auto ();
+ tree decomp_type = cp_build_reference_type (auto_node, true);
+ decomp_type = do_auto_deduction (decomp_type, expansion_init, auto_node);
+ tree decl = build_decl (loc, VAR_DECL, NULL_TREE, decomp_type);
+ TREE_USED (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_DECLARED_CONSTEXPR_P (decl)
+ = DECL_DECLARED_CONSTEXPR_P (range_decl);
+ if (DECL_DECLARED_CONSTEXPR_P (decl))
+ TREE_READONLY (decl) = 1;
+ if (n)
+ fit_decomposition_lang_decl (decl, NULL_TREE);
+ pushdecl (decl);
+ cp_decomp this_decomp;
+ this_decomp.count = n;
+ destruct_decls.safe_grow (n, true);
+ for (unsigned HOST_WIDE_INT i = 0; i < n; ++i)
+ {
+ tree this_decl = build_decl (loc, VAR_DECL, NULL_TREE, make_auto ());
+ TREE_USED (this_decl) = 1;
+ DECL_ARTIFICIAL (this_decl) = 1;
+ DECL_DECLARED_CONSTEXPR_P (this_decl)
+ = DECL_DECLARED_CONSTEXPR_P (decl);
+ if (DECL_DECLARED_CONSTEXPR_P (decl))
+ TREE_READONLY (this_decl) = 1;
+ pushdecl (this_decl);
+ this_decomp.decl = this_decl;
+ destruct_decls[i] = this_decl;
+ }
+ DECL_NAME (decl) = for_range__identifier;
+ cp_finish_decl (decl, expansion_init,
+ /*is_constant_init*/false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING, n ? &this_decomp : NULL);
+ DECL_NAME (decl) = NULL_TREE;
+ }
+
+ expansion_stmt_bc bc_data = { NULL_TREE, NULL_TREE, NULL, loc, false };
+
+ for (unsigned HOST_WIDE_INT i = 0; i < n; ++i)
+ {
+ tree scope = do_pushlevel (sk_block);
+ bool revert_outer
+ = (current_binding_level->level_chain
+ && current_binding_level->level_chain->kind == sk_template_for);
+ /* Don't diagnose redeclaration of for-range-declaration decls.
+ The sk_template_for block is reused for the originally parsed
+ source as well as the lowered one. In the original one
+ redeclaration of the for-range-declaration decls in the substatement
+ should be diagnosed (i.e. declarations of the same name in sk_block
+ of the body vs. declarations in sk_template_for block). In the
+ lowered case, the sk_block added by do_pushlevel (sk_block) above
+ will be block in the lowering of each Si. Those blocks do redeclare
+ for-range-declaration, so temporarily change sk_template_for
+ kind to sk_block to avoid it being diagnosed as invalid. */
+ if (revert_outer)
+ current_binding_level->level_chain->kind = sk_block;
+ tree type = TREE_TYPE (range_decl);
+ if (args)
+ type = tsubst (type, args, complain | tf_tst_ok, in_decl);
+ tree decl = build_decl (loc, VAR_DECL, DECL_NAME (range_decl), type);
+ DECL_ATTRIBUTES (decl) = DECL_ATTRIBUTES (range_decl);
+ if (args)
+ apply_late_template_attributes (&decl, DECL_ATTRIBUTES (decl),
+ /*flags=*/0, args, complain,
+ in_decl);
+
+ DECL_DECLARED_CONSTEXPR_P (decl)
+ = DECL_DECLARED_CONSTEXPR_P (range_decl);
+ if (DECL_DECLARED_CONSTEXPR_P (decl))
+ TREE_READONLY (decl) = 1;
+ pushdecl (decl);
+ tree init = NULL_TREE;
+ switch (kind)
+ {
+ case esk_enumerating:
+ init = CONSTRUCTOR_ELT (expansion_init, i)->value;
+ break;
+ case esk_iterating:
+ tree iter_init, auto_node, iter_type, iter;
+ iter_init
+ = build_x_binary_op (loc, PLUS_EXPR, begin, ERROR_MARK,
+ build_int_cst (ptrdiff_type_node, i),
+ ERROR_MARK, NULL_TREE, NULL,
+ tf_warning_or_error);
+ auto_node = make_auto ();
+ iter_type = do_auto_deduction (auto_node, iter_init, auto_node);
+ iter = build_decl (loc, VAR_DECL, NULL_TREE, iter_type);
+ TREE_USED (iter) = 1;
+ DECL_ARTIFICIAL (iter) = 1;
+ TREE_STATIC (iter) = 1;
+ DECL_DECLARED_CONSTEXPR_P (iter) = 1;
+ pushdecl (iter);
+ cp_finish_decl (iter, iter_init, /*is_constant_init*/false,
+ NULL_TREE, LOOKUP_ONLYCONVERTING);
+ init = build_x_indirect_ref (loc, iter, RO_UNARY_STAR, NULL_TREE,
+ tf_warning_or_error);
+ break;
+ case esk_destructuring:
+ init = convert_from_reference (destruct_decls[i]);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ cp_decomp this_decomp = {};
+ if (is_decomp)
+ {
+ fit_decomposition_lang_decl (decl, NULL_TREE);
+ tree v = TEMPLATE_FOR_DECL (expansion_stmt);
+ this_decomp.count = TREE_VEC_LENGTH (v) - 1;
+ for (unsigned i = 0; i < this_decomp.count; ++i)
+ {
+ tree this_decl
+ = build_decl (loc, VAR_DECL,
+ DECL_NAME (TREE_VEC_ELT (v, i + 1)),
+ make_auto ());
+ TREE_USED (this_decl) = 1;
+ DECL_ARTIFICIAL (this_decl) = 1;
+ DECL_ATTRIBUTES (this_decl)
+ = DECL_ATTRIBUTES (TREE_VEC_ELT (v, i + 1));
+ if (DECL_PACK_P (TREE_VEC_ELT (v, i + 1)))
+ {
+ tree dtype = cxx_make_type (DECLTYPE_TYPE);
+ DECLTYPE_TYPE_EXPR (dtype) = this_decl;
+ DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (dtype) = 1;
+ SET_TYPE_STRUCTURAL_EQUALITY (dtype);
+ tree type = cxx_make_type (TYPE_PACK_EXPANSION);
+ PACK_EXPANSION_PATTERN (type) = dtype;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+ PACK_EXPANSION_PARAMETER_PACKS (type) = this_decl;
+ TREE_TYPE (this_decl) = type;
+ }
+ if (args)
+ apply_late_template_attributes (&this_decl,
+ DECL_ATTRIBUTES (this_decl),
+ /*flags=*/0, args,
+ complain, in_decl);
+ DECL_DECLARED_CONSTEXPR_P (this_decl)
+ = DECL_DECLARED_CONSTEXPR_P (decl);
+ if (DECL_DECLARED_CONSTEXPR_P (decl))
+ TREE_READONLY (this_decl) = 1;
+ pushdecl (this_decl);
+ this_decomp.decl = this_decl;
+ }
+ }
+ cp_finish_decl (decl, init, false, NULL_TREE,
+ LOOKUP_ONLYCONVERTING, is_decomp ? &this_decomp : NULL);
+ if (revert_outer)
+ current_binding_level->level_chain->kind = sk_template_for;
+ tree targs = args;
+ if (args == NULL_TREE)
+ {
+ targs = make_tree_vec (1);
+ TREE_VEC_ELT (targs, 0) = build_int_cst (ptrdiff_type_node, i + 1);
+ }
+ if (args != NULL_TREE
+ || push_tinst_level_loc (expansion_stmt, targs, loc))
+ {
+ local_specialization_stack lss (lss_copy);
+ register_local_specialization (decl, range_decl);
+ if (is_decomp)
+ {
+ tree d = this_decomp.decl;
+ unsigned int cnt = this_decomp.count;
+ tree v = TEMPLATE_FOR_DECL (expansion_stmt);
+ for (unsigned int i = 0; i < cnt; ++i, d = DECL_CHAIN (d))
+ register_local_specialization (d, TREE_VEC_ELT (v, cnt - i));
+ }
+ tsubst_stmt (TEMPLATE_FOR_BODY (expansion_stmt),
+ targs, complain, in_decl ? in_decl : range_decl);
+ if (args == NULL_TREE)
+ pop_tinst_level ();
+ }
+ tree stmt = do_poplevel (scope);
+ if (stmt)
+ {
+ add_stmt (stmt);
+ hash_set<tree> pset;
+ bc_data.continue_label = NULL_TREE;
+ bc_data.pset = &pset;
+ cp_walk_tree (&stmt, expansion_stmt_find_bc_r, &bc_data, &pset);
+ if (bc_data.continue_label)
+ add_stmt (build1 (LABEL_EXPR, void_type_node,
+ bc_data.continue_label));
+ }
+ }
+ if (bc_data.break_label)
+ add_stmt (build1 (LABEL_EXPR, void_type_node, bc_data.break_label));
+ if (args == NULL_TREE)
+ {
+ TREE_TYPE (range_decl) = error_mark_node;
+ if (DECL_HAS_VALUE_EXPR_P (range_decl))
+ {
+ SET_DECL_VALUE_EXPR (range_decl, NULL_TREE);
+ DECL_HAS_VALUE_EXPR_P (range_decl) = 0;
+ }
+ if (is_decomp)
+ {
+ tree v = TEMPLATE_FOR_DECL (expansion_stmt);
+ for (int i = 1; i < TREE_VEC_LENGTH (v); ++i)
+ {
+ tree d = TREE_VEC_ELT (v, i);
+ TREE_TYPE (d) = error_mark_node;
+ if (DECL_HAS_VALUE_EXPR_P (d))
+ {
+ SET_DECL_VALUE_EXPR (d, NULL_TREE);
+ DECL_HAS_VALUE_EXPR_P (d) = 0;
+ }
+ }
+ }
+ }
+}
+
/* Set up the hash tables for template instantiations. */
void
diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc
index cea9f7c..77b5b1d 100644
--- a/gcc/cp/search.cc
+++ b/gcc/cp/search.cc
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "tree-inline.h"
+#include "contracts.h"
static int is_subobject_of_p (tree, tree);
static tree dfs_lookup_base (tree, void *);
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 52ecac4..1937ace 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "predict.h"
#include "memmodel.h"
#include "gimplify.h"
+#include "contracts.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
@@ -677,7 +678,7 @@ do_poplevel (tree stmt_list)
/* Begin a new scope. */
-static tree
+tree
do_pushlevel (scope_kind sk)
{
tree ret = push_stmt_list ();
@@ -1854,6 +1855,21 @@ finish_range_for_decl (tree range_for_stmt, tree decl, tree expr)
RANGE_FOR_BODY (range_for_stmt) = do_pushlevel (sk_block);
}
+/* Begin the scope of an expansion-statement. */
+
+tree
+begin_template_for_scope (tree *init)
+{
+ tree scope = do_pushlevel (sk_template_for);
+
+ if (processing_template_decl)
+ *init = push_stmt_list ();
+ else
+ *init = NULL_TREE;
+
+ return scope;
+}
+
/* Finish a break-statement. */
tree
@@ -3992,9 +4008,15 @@ finish_compound_literal (tree type, tree compound_literal,
tree
finish_fname (tree id)
{
- tree decl;
-
- decl = fname_decl (input_location, C_RID_CODE (id), id);
+ tree decl = fname_decl (input_location, C_RID_CODE (id), id);
+ /* [expr.prim.lambda.closure]/16 "Unless the compound-statement is that
+ of a consteval-block-declaration, a variable __func__ is implicitly
+ defined...". We could be in a consteval block in a function, though,
+ and then we shouldn't warn. */
+ if (current_function_decl
+ && !current_nonlambda_function (/*only_skip_consteval_block_p=*/true))
+ pedwarn (input_location, 0, "%qD is not defined outside of function scope",
+ decl);
if (processing_template_decl && current_function_decl
&& decl != error_mark_node)
decl = DECL_NAME (decl);
@@ -4490,6 +4512,17 @@ baselink_for_fns (tree fns)
return build_baselink (conv_path, access_path, fns, /*optype=*/NULL_TREE);
}
+/* Returns true iff we are currently parsing a lambda-declarator. */
+
+static bool
+parsing_lambda_declarator ()
+{
+ cp_binding_level *b = current_binding_level;
+ while (b->kind == sk_template_parms || b->kind == sk_function_parms)
+ b = b->level_chain;
+ return b->kind == sk_lambda;
+}
+
/* Returns true iff DECL is a variable from a function outside
the current one. */
@@ -4504,7 +4537,15 @@ outer_var_p (tree decl)
/* Don't get confused by temporaries. */
&& DECL_NAME (decl)
&& (DECL_CONTEXT (decl) != current_function_decl
- || parsing_nsdmi ()));
+ || parsing_nsdmi ()
+ /* Also consider captures as outer vars if we are in
+ decltype in a lambda declarator as in:
+ auto l = [j=0]() -> decltype((j)) { ... }
+ for the sake of finish_decltype_type.
+
+ (Similar issue also affects non-lambdas, but vexing parse
+ makes it more difficult to handle than lambdas.) */
+ || parsing_lambda_declarator ()));
}
/* As above, but also checks that DECL is automatic. */
@@ -4550,7 +4591,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)
if (!mark_used (decl, complain))
return error_mark_node;
- if (parsing_nsdmi ())
+ if (parsing_nsdmi () || parsing_lambda_declarator ())
containing_function = NULL_TREE;
if (containing_function && LAMBDA_FUNCTION_P (containing_function))
@@ -7745,7 +7786,14 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
/* We've reached the end of a list of expanded nodes. Reset the group
start pointer. */
if (c == grp_sentinel)
- grp_start_p = NULL;
+ {
+ if (grp_start_p
+ && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p))
+ for (tree gc = *grp_start_p; gc != grp_sentinel;
+ gc = OMP_CLAUSE_CHAIN (gc))
+ OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p);
+ grp_start_p = NULL;
+ }
switch (OMP_CLAUSE_CODE (c))
{
@@ -8997,6 +9045,13 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
/* FALLTHRU */
case OMP_CLAUSE_TO:
case OMP_CLAUSE_FROM:
+ if (OMP_CLAUSE_ITERATORS (c)
+ && cp_omp_finish_iterators (OMP_CLAUSE_ITERATORS (c)))
+ {
+ t = error_mark_node;
+ break;
+ }
+ /* FALLTHRU */
case OMP_CLAUSE__CACHE_:
{
using namespace omp_addr_tokenizer;
@@ -9900,6 +9955,11 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
pc = &OMP_CLAUSE_CHAIN (c);
}
+ if (grp_start_p
+ && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p))
+ for (tree gc = *grp_start_p; gc; gc = OMP_CLAUSE_CHAIN (gc))
+ OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p);
+
if (reduction_seen < 0 && (ordered_seen || schedule_seen))
reduction_seen = -2;
@@ -12598,11 +12658,14 @@ cexpr_str::extract (location_t location, const char * & msg, int &len)
CONDITION and the message text MESSAGE. LOCATION is the location
of the static assertion in the source code. When MEMBER_P, this
static assertion is a member of a class. If SHOW_EXPR_P is true,
- print the condition (because it was instantiation-dependent). */
+ print the condition (because it was instantiation-dependent).
+ If CONSTEVAL_BLOCK_P is true, this static assertion represents
+ a consteval block. */
void
finish_static_assert (tree condition, tree message, location_t location,
- bool member_p, bool show_expr_p)
+ bool member_p, bool show_expr_p,
+ bool consteval_block_p/*=false*/)
{
tsubst_flags_t complain = tf_warning_or_error;
@@ -12630,6 +12693,7 @@ finish_static_assert (tree condition, tree message, location_t location,
STATIC_ASSERT_CONDITION (assertion) = orig_condition;
STATIC_ASSERT_MESSAGE (assertion) = cstr.message;
STATIC_ASSERT_SOURCE_LOCATION (assertion) = location;
+ CONSTEVAL_BLOCK_P (assertion) = consteval_block_p;
if (member_p)
maybe_add_class_template_decl_list (current_class_type,
@@ -12641,6 +12705,13 @@ finish_static_assert (tree condition, tree message, location_t location,
return;
}
+ /* Evaluate the consteval { }. This must be done only once. */
+ if (consteval_block_p)
+ {
+ cxx_constant_value (condition);
+ return;
+ }
+
/* Fold the expression and convert it to a boolean value. */
condition = contextual_conv_bool (condition, complain);
condition = fold_non_dependent_expr (condition, complain,
@@ -12890,9 +12961,9 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
}
else
{
- if (outer_automatic_var_p (STRIP_REFERENCE_REF (expr))
- && current_function_decl
- && LAMBDA_FUNCTION_P (current_function_decl))
+ tree decl = STRIP_REFERENCE_REF (expr);
+ tree lam = current_lambda_expr ();
+ if (lam && outer_automatic_var_p (decl))
{
/* [expr.prim.id.unqual]/3: If naming the entity from outside of an
unevaluated operand within S would refer to an entity captured by
@@ -12909,8 +12980,6 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
local variable inside decltype, not just decltype((x)) (PR83167).
And we don't handle nested lambdas properly, where we need to
consider the outer lambdas as well (PR112926). */
- tree decl = STRIP_REFERENCE_REF (expr);
- tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl));
tree cap = lookup_name (DECL_NAME (decl), LOOK_where::BLOCK,
LOOK_want::HIDDEN_LAMBDA);
@@ -12926,17 +12995,28 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
if (type && !TYPE_REF_P (type))
{
- tree obtype = TREE_TYPE (DECL_ARGUMENTS (current_function_decl));
- if (WILDCARD_TYPE_P (non_reference (obtype)))
- /* We don't know what the eventual obtype quals will be. */
- goto dependent;
- auto direct_type = [](tree t){
- if (INDIRECT_TYPE_P (t))
- return TREE_TYPE (t);
- return t;
- };
- int const quals = cp_type_quals (type)
- | cp_type_quals (direct_type (obtype));
+ int quals;
+ if (current_function_decl
+ && LAMBDA_FUNCTION_P (current_function_decl)
+ && DECL_XOBJ_MEMBER_FUNCTION_P (current_function_decl))
+ {
+ tree obtype = TREE_TYPE (DECL_ARGUMENTS (current_function_decl));
+ if (WILDCARD_TYPE_P (non_reference (obtype)))
+ /* We don't know what the eventual obtype quals will be. */
+ goto dependent;
+ auto direct_type = [](tree t){
+ if (INDIRECT_TYPE_P (t))
+ return TREE_TYPE (t);
+ return t;
+ };
+ quals = (cp_type_quals (type)
+ | cp_type_quals (direct_type (obtype)));
+ }
+ else
+ /* We are in the parameter clause, trailing return type, or
+ the requires clause and have no relevant c_f_decl yet. */
+ quals = (LAMBDA_EXPR_CONST_QUAL_P (lam)
+ ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
type = cp_build_qualified_type (type, quals);
type = build_reference_type (type);
}
@@ -13631,10 +13711,11 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_DEDUCIBLE:
return type_targs_deducible_from (type1, type2);
- /* __array_rank and __builtin_type_order are handled in
- finish_trait_expr. */
+ /* __array_rank, __builtin_type_order and __builtin_structured_binding_size
+ are handled in finish_trait_expr. */
case CPTK_RANK:
case CPTK_TYPE_ORDER:
+ case CPTK_STRUCTURED_BINDING_SIZE:
gcc_unreachable ();
#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
@@ -13739,6 +13820,27 @@ same_type_ref_bind_p (cp_trait_kind kind, tree type1, tree type2)
(non_reference (to), non_reference (from))));
}
+/* Helper for finish_trait_expr and tsubst_expr. Handle
+ CPTK_STRUCTURED_BINDING_SIZE in possibly SFINAE-friendly
+ way. */
+
+tree
+finish_structured_binding_size (location_t loc, tree type,
+ tsubst_flags_t complain)
+{
+ if (TYPE_REF_P (type))
+ {
+ if (complain & tf_error)
+ error_at (loc, "%qs argument %qT is a reference",
+ "__builtin_structured_binding_size", type);
+ return error_mark_node;
+ }
+ HOST_WIDE_INT ret = cp_decomp_size (loc, type, complain);
+ if (ret == -1)
+ return error_mark_node;
+ return maybe_wrap_with_location (build_int_cst (size_type_node, ret), loc);
+}
+
/* Process a trait expression. */
tree
@@ -13751,7 +13853,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
if (processing_template_decl)
{
tree trait_expr = make_node (TRAIT_EXPR);
- if (kind == CPTK_RANK)
+ if (kind == CPTK_RANK || kind == CPTK_STRUCTURED_BINDING_SIZE)
TREE_TYPE (trait_expr) = size_type_node;
else if (kind == CPTK_TYPE_ORDER)
{
@@ -13868,9 +13970,22 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_UNBOUNDED_ARRAY:
case CPTK_IS_UNION:
case CPTK_IS_VOLATILE:
+ break;
+
case CPTK_RANK:
+ {
+ size_t rank = 0;
+ for (; TREE_CODE (type1) == ARRAY_TYPE; type1 = TREE_TYPE (type1))
+ ++rank;
+ return maybe_wrap_with_location (build_int_cst (size_type_node, rank),
+ loc);
+ }
+
case CPTK_TYPE_ORDER:
- break;
+ return maybe_wrap_with_location (type_order_value (type1, type2), loc);
+
+ case CPTK_STRUCTURED_BINDING_SIZE:
+ return finish_structured_binding_size (loc, type1, tf_warning_or_error);
case CPTK_IS_LAYOUT_COMPATIBLE:
if (!array_of_unknown_bound_p (type1)
@@ -13901,20 +14016,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
gcc_unreachable ();
}
- tree val;
- if (kind == CPTK_RANK)
- {
- size_t rank = 0;
- for (; TREE_CODE (type1) == ARRAY_TYPE; type1 = TREE_TYPE (type1))
- ++rank;
- val = build_int_cst (size_type_node, rank);
- }
- else if (kind == CPTK_TYPE_ORDER)
- val = type_order_value (type1, type2);
- else
- val = (trait_expr_value (kind, type1, type2)
- ? boolean_true_node : boolean_false_node);
-
+ tree val = (trait_expr_value (kind, type1, type2)
+ ? boolean_true_node : boolean_false_node);
return maybe_wrap_with_location (val, loc);
}
@@ -14111,7 +14214,7 @@ apply_deduced_return_type (tree fco, tree return_type)
result);
DECL_RESULT (fco) = result;
- if (!processing_template_decl)
+ if (!uses_template_parms (fco))
if (function *fun = DECL_STRUCT_FUNCTION (fco))
{
bool aggr = aggregate_value_p (result, fco);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index d56d73f..e354da0 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -1186,7 +1186,12 @@ build_cplus_array_type (tree elt_type, tree index_type, int dependent)
for (t = m; t; t = TYPE_NEXT_VARIANT (t))
if (TREE_TYPE (t) == elt_type
&& TYPE_NAME (t) == NULL_TREE
- && TYPE_ATTRIBUTES (t) == NULL_TREE)
+ && TYPE_ATTRIBUTES (t) == NULL_TREE
+ && (!TYPE_USER_ALIGN (t)
+ || (TYPE_USER_ALIGN (elt_type)
+ && TYPE_ALIGN (t) == TYPE_ALIGN (elt_type)))
+ && !TREE_DEPRECATED (t)
+ && !TREE_UNAVAILABLE (t))
break;
if (!t)
{
@@ -6394,8 +6399,8 @@ decl_linkage (tree decl)
if (NAMESPACE_SCOPE_P (decl)
&& (!DECL_NAME (decl) || IDENTIFIER_ANON_P (DECL_NAME (decl))))
{
- if (TREE_CODE (decl) == TYPE_DECL && !TYPE_ANON_P (TREE_TYPE (decl)))
- /* This entity has a typedef name for linkage purposes. */;
+ if (TREE_CODE (decl) == TYPE_DECL && !TYPE_UNNAMED_P (TREE_TYPE (decl)))
+ /* This entity has a name for linkage purposes. */;
else if (DECL_DECOMPOSITION_P (decl) && DECL_DECOMP_IS_BASE (decl))
/* Namespace-scope structured bindings can have linkage. */;
else if (TREE_CODE (decl) == NAMESPACE_DECL && cxx_dialect >= cxx11)
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index f592894..ccfe50d 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -3973,7 +3973,6 @@ tree
cp_build_array_ref (location_t loc, tree array, tree idx,
tsubst_flags_t complain)
{
- tree first = NULL_TREE;
tree ret;
if (idx == 0)
@@ -3987,6 +3986,21 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
|| TREE_TYPE (idx) == error_mark_node)
return error_mark_node;
+ /* 0[array] */
+ if (TREE_CODE (TREE_TYPE (idx)) == ARRAY_TYPE)
+ {
+ std::swap (array, idx);
+
+ tree first = NULL_TREE;
+ if (flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (array))
+ idx = first = save_expr (idx);
+ ret = cp_build_array_ref (loc, array, idx, complain);
+
+ if (first)
+ ret = build2 (COMPOUND_EXPR, TREE_TYPE (ret), first, ret);
+ return ret;
+ }
+
/* If ARRAY is a COMPOUND_EXPR or COND_EXPR, move our reference
inside it. */
switch (TREE_CODE (array))
@@ -4066,14 +4080,6 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
bool non_lvalue = convert_vector_to_array_for_subscript (loc, &array, idx);
- /* 0[array] */
- if (TREE_CODE (TREE_TYPE (idx)) == ARRAY_TYPE)
- {
- std::swap (array, idx);
- if (flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (array))
- idx = first = save_expr (idx);
- }
-
if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
{
tree rval, type;
@@ -4149,17 +4155,16 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
protected_set_expr_location (ret, loc);
if (non_lvalue)
ret = non_lvalue_loc (loc, ret);
- if (first)
- ret = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (ret), first, ret);
return ret;
}
{
tree ar = cp_default_conversion (array, complain);
tree ind = cp_default_conversion (idx, complain);
+ tree first = NULL_TREE;
- if (!processing_template_decl
- && !first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
+ if (!processing_template_decl && flag_strong_eval_order == 2
+ && TREE_SIDE_EFFECTS (ind))
ar = first = save_expr (ar);
/* Put the integer in IND to simplify error checking. */
@@ -4287,7 +4292,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function,
idx = build1 (NOP_EXPR, vtable_index_type, e3);
switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
{
- int flag_sanitize_save;
+ sanitize_code_type flag_sanitize_save;
case ptrmemfunc_vbit_in_pfn:
e1 = cp_build_binary_op (input_location,
BIT_AND_EXPR, idx, integer_one_node,
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index faaf1df..d77de92 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -281,15 +281,96 @@ cxx_incomplete_type_inform (const_tree type)
location_t loc = DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type));
tree ptype = strip_top_quals (CONST_CAST_TREE (type));
+ /* When defining a template, current_class_type will be the pattern on
+ the template definition, while non-self-reference usages of this
+ template will be an instantiation; we should pull out the pattern to
+ compare against. And for partial specs we should use the loc of the
+ partial spec rather than the primary template. */
+ tree ttype = NULL_TREE;
+ tree tinfo = TYPE_TEMPLATE_INFO (ptype);
+ if (tinfo)
+ {
+ tree tmpl = TI_TEMPLATE (tinfo);
+ if (PRIMARY_TEMPLATE_P (tmpl) && TI_PARTIAL_INFO (tinfo))
+ {
+ tree partial = TI_TEMPLATE (TI_PARTIAL_INFO (tinfo));
+ loc = DECL_SOURCE_LOCATION (partial);
+ ttype = TREE_TYPE (partial);
+ }
+ else
+ ttype = TREE_TYPE (tmpl);
+ }
+
if (current_class_type
&& TYPE_BEING_DEFINED (current_class_type)
- && same_type_p (ptype, current_class_type))
+ && (same_type_p (ptype, current_class_type)
+ || (ttype && same_type_p (ttype, current_class_type))))
inform (loc, "definition of %q#T is not complete until "
"the closing brace", ptype);
- else if (!TYPE_TEMPLATE_INFO (ptype))
- inform (loc, "forward declaration of %q#T", ptype);
else
- inform (loc, "declaration of %q#T", ptype);
+ {
+ if (!tinfo)
+ inform (loc, "forward declaration of %q#T", ptype);
+ else
+ inform (loc, "declaration of %q#T", ptype);
+
+ /* If there's a similar-looking complete type attached
+ to a different module, point at that as a suggestion. */
+ if (modules_p () && TYPE_NAMESPACE_SCOPE_P (ptype))
+ {
+ tree result = lookup_qualified_name (CP_TYPE_CONTEXT (ptype),
+ TYPE_IDENTIFIER (ptype),
+ LOOK_want::TYPE);
+ if (TREE_CODE (result) == TREE_LIST)
+ for (; result; result = TREE_CHAIN (result))
+ {
+ tree cand = TREE_VALUE (result);
+
+ /* Typedefs are not likely intended to correspond. */
+ if (is_typedef_decl (STRIP_TEMPLATE (cand))
+ || DECL_ALIAS_TEMPLATE_P (cand))
+ continue;
+
+ /* Only look at templates if type was a template. */
+ if ((tinfo != nullptr) != (TREE_CODE (cand) == TEMPLATE_DECL))
+ continue;
+
+ /* If we're looking for a template specialisation,
+ only consider matching specialisations. */
+ if (tinfo)
+ {
+ tree t = lookup_template_class (cand, TI_ARGS (tinfo),
+ NULL_TREE, NULL_TREE,
+ tf_none);
+ if (t == error_mark_node
+ || !CLASS_TYPE_P (t)
+ || TYPE_BEING_DEFINED (t))
+ continue;
+
+ if (CLASSTYPE_TEMPLATE_INSTANTIATION (t))
+ {
+ /* An uninstantiated template: check if there is a
+ pattern that could be used. We don't want to
+ call instantiate_class_template as that could
+ cause further errors; this is just a hint. */
+ tree part = most_specialized_partial_spec (t, tf_none);
+ cand = (part ? TI_TEMPLATE (part)
+ : CLASSTYPE_TI_TEMPLATE (t));
+ }
+ else
+ cand = TYPE_NAME (t);
+ }
+
+ if (!COMPLETE_TYPE_P (TREE_TYPE (cand)))
+ continue;
+
+ inform (DECL_SOURCE_LOCATION (cand),
+ "%q#T has a definition but does not correspond with "
+ "%q#T because it is attached to a different module",
+ TREE_TYPE (cand), ptype);
+ }
+ }
+ }
}
/* Print an error message for invalid use of an incomplete type.