diff options
Diffstat (limited to 'gcc')
24 files changed, 531 insertions, 43 deletions
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index f6db36e..02bc149 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -308,6 +308,9 @@ UNSPECV_SPLIT_STACK_CALL UNSPECV_OSC_BREAK + + ; Stack Protector + UNSPECV_SP_GET_TP ]) ;; @@ -365,6 +368,9 @@ (VR23_REGNUM 45) (VR24_REGNUM 46) (VR31_REGNUM 53) + ; Access registers + (AR0_REGNUM 36) + (AR1_REGNUM 37) ]) ; Rounding modes for binary floating point numbers @@ -11924,15 +11930,43 @@ ; Stack Protector Patterns ; +; Insns stack_protect_get_tp{si,di} are similar to *get_tp_{31,64} but still +; distinct in the sense that they force recomputation of the thread pointer +; instead of potentially reloading it from stack. + +(define_insn_and_split "stack_protect_get_tpsi" + [(set (match_operand:SI 0 "register_operand" "=d") + (unspec_volatile:SI [(const_int 0)] UNSPECV_SP_GET_TP))] + "" + "#" + "&& reload_completed" + [(set (match_dup 0) (reg:SI AR0_REGNUM))]) + +(define_insn_and_split "stack_protect_get_tpdi" + [(set (match_operand:DI 0 "register_operand" "=d") + (unspec_volatile:DI [(const_int 0)] UNSPECV_SP_GET_TP))] + "" + "#" + "&& reload_completed" + [(set (match_dup 1) (reg:SI AR0_REGNUM)) + (set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32))) + (set (strict_low_part (match_dup 1)) (reg:SI AR1_REGNUM))] + "operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]));") + (define_expand "stack_protect_set" [(set (match_operand 0 "memory_operand" "") (match_operand 1 "memory_operand" ""))] "" { #ifdef TARGET_THREAD_SSP_OFFSET + rtx tp = gen_reg_rtx (Pmode); + if (TARGET_64BIT) + emit_insn (gen_stack_protect_get_tpdi (tp)); + else + emit_insn (gen_stack_protect_get_tpsi (tp)); operands[1] - = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), - GEN_INT (TARGET_THREAD_SSP_OFFSET))); + = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, tp, + GEN_INT (TARGET_THREAD_SSP_OFFSET))); #endif if (TARGET_64BIT) emit_insn (gen_stack_protect_setdi (operands[0], operands[1])); @@ -11958,9 +11992,14 @@ { rtx cc_reg, test; #ifdef TARGET_THREAD_SSP_OFFSET + rtx tp = gen_reg_rtx (Pmode); + if (TARGET_64BIT) + emit_insn (gen_stack_protect_get_tpdi (tp)); + else + emit_insn (gen_stack_protect_get_tpsi (tp)); operands[1] - = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, s390_get_thread_pointer (), - GEN_INT (TARGET_THREAD_SSP_OFFSET))); + = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, tp, + GEN_INT (TARGET_THREAD_SSP_OFFSET))); #endif if (TARGET_64BIT) emit_insn (gen_stack_protect_testdi (operands[0], operands[1])); diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index 8c43a69..b75cec1 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -423,12 +423,13 @@ xtensa_uimm8x4 (HOST_WIDE_INT v) } -static bool -xtensa_b4const (HOST_WIDE_INT v) +bool +xtensa_b4const_or_zero (HOST_WIDE_INT v) { switch (v) { case -1: + case 0: case 1: case 2: case 3: @@ -451,15 +452,6 @@ xtensa_b4const (HOST_WIDE_INT v) bool -xtensa_b4const_or_zero (HOST_WIDE_INT v) -{ - if (v == 0) - return true; - return xtensa_b4const (v); -} - - -bool xtensa_b4constu (HOST_WIDE_INT v) { switch (v) @@ -4512,7 +4504,8 @@ xtensa_rtx_costs (rtx x, machine_mode mode, int outer_code, } break; case COMPARE: - if ((INTVAL (x) == 0) || xtensa_b4const (INTVAL (x))) + if (xtensa_b4const_or_zero (INTVAL (x)) + || xtensa_b4constu (INTVAL (x))) { *total = 0; return true; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1b893e2..3b92d9a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -506,6 +506,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR) TARGET_EXPR_ELIDING_P (in TARGET_EXPR) contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT) + TYPENAME_IS_UNION_P (in TYPENAME_TYPE) 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, CALL_EXPR, or FIELD_DECL). @@ -2354,6 +2355,10 @@ enum languages { lang_c, lang_cplusplus }; #define NON_UNION_CLASS_TYPE_P(T) \ (TREE_CODE (T) == RECORD_TYPE && TYPE_LANG_FLAG_5 (T)) +/* Nonzero if T is a class type and is a union. */ +#define UNION_TYPE_P(T) \ + (TREE_CODE (T) == UNION_TYPE && TYPE_LANG_FLAG_5 (T)) + /* Keep these checks in ascending code order. */ #define RECORD_OR_UNION_CODE_P(T) \ ((T) == RECORD_TYPE || (T) == UNION_TYPE) @@ -4485,11 +4490,14 @@ get_vec_init_expr (tree t) #define TYPENAME_IS_ENUM_P(NODE) \ (TREE_LANG_FLAG_0 (TYPENAME_TYPE_CHECK (NODE))) -/* True if a TYPENAME_TYPE was declared as a "class", "struct", or - "union". */ +/* True if a TYPENAME_TYPE was declared as a "class" or "struct". */ #define TYPENAME_IS_CLASS_P(NODE) \ (TREE_LANG_FLAG_1 (TYPENAME_TYPE_CHECK (NODE))) +/* True if a TYPENAME_TYPE was declared as a "union". */ +#define TYPENAME_IS_UNION_P(NODE) \ + (TREE_LANG_FLAG_3 (TYPENAME_TYPE_CHECK (NODE))) + /* True if a TYPENAME_TYPE is in the process of being resolved. */ #define TYPENAME_IS_RESOLVING_P(NODE) \ (TREE_LANG_FLAG_2 (TYPENAME_TYPE_CHECK (NODE))) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index be26bd3..0e6afbe 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -4370,6 +4370,7 @@ struct typename_info { tree template_id; bool enum_p; bool class_p; + bool union_p; }; struct typename_hasher : ggc_ptr_hash<tree_node> @@ -4408,7 +4409,8 @@ struct typename_hasher : ggc_ptr_hash<tree_node> && TYPE_CONTEXT (t1) == t2->scope && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id && TYPENAME_IS_ENUM_P (t1) == t2->enum_p - && TYPENAME_IS_CLASS_P (t1) == t2->class_p); + && TYPENAME_IS_CLASS_P (t1) == t2->class_p + && TYPENAME_IS_UNION_P (t1) == t2->union_p); } }; @@ -4432,9 +4434,8 @@ build_typename_type (tree context, tree name, tree fullname, ti.name = name; ti.template_id = fullname; ti.enum_p = tag_type == enum_type; - ti.class_p = (tag_type == class_type - || tag_type == record_type - || tag_type == union_type); + ti.class_p = (tag_type == class_type || tag_type == record_type); + ti.union_p = tag_type == union_type; hashval_t hash = typename_hasher::hash (&ti); /* See if we already have this type. */ @@ -4450,6 +4451,7 @@ build_typename_type (tree context, tree name, tree fullname, TYPENAME_TYPE_FULLNAME (t) = ti.template_id; TYPENAME_IS_ENUM_P (t) = ti.enum_p; TYPENAME_IS_CLASS_P (t) = ti.class_p; + TYPENAME_IS_UNION_P (t) = ti.union_p; /* Build the corresponding TYPE_DECL. */ tree d = build_decl (input_location, TYPE_DECL, name, t); @@ -9174,6 +9176,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, if (decomp) { + if (DECL_DECLARED_CONSTINIT_P (decl) && cxx_dialect < cxx26) + pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions, + "%<constinit%> can be applied to structured binding " + "only with %<-std=c++2c%> or %<-std=gnu++2c%>"); cp_maybe_mangle_decomp (decl, decomp); if (TREE_STATIC (decl) && !DECL_FUNCTION_SCOPE_P (decl)) { @@ -13621,9 +13627,10 @@ grokdeclarator (const cp_declarator *declarator, if (typedef_p) error_at (declspecs->locations[ds_typedef], "structured binding declaration cannot be %qs", "typedef"); - if (constexpr_p && !concept_p) - error_at (declspecs->locations[ds_constexpr], "structured " - "binding declaration cannot be %qs", "constexpr"); + if (constexpr_p && !concept_p && cxx_dialect < cxx26) + pedwarn (declspecs->locations[ds_constexpr], OPT_Wc__26_extensions, + "structured binding declaration can be %qs only with " + "%<-std=c++2c%> or %<-std=gnu++2c%>", "constexpr"); if (consteval_p) error_at (declspecs->locations[ds_consteval], "structured " "binding declaration cannot be %qs", "consteval"); @@ -13634,8 +13641,11 @@ grokdeclarator (const cp_declarator *declarator, declspecs->gnu_thread_keyword_p ? "__thread" : "thread_local"); if (concept_p) - error_at (declspecs->locations[ds_concept], - "structured binding declaration cannot be %qs", "concept"); + { + error_at (declspecs->locations[ds_concept], + "structured binding declaration cannot be %qs", "concept"); + constexpr_p = 0; + } /* [dcl.struct.bind] "A cv that includes volatile is deprecated." */ if (type_quals & TYPE_QUAL_VOLATILE) warning_at (declspecs->locations[ds_volatile], OPT_Wvolatile, @@ -13690,7 +13700,6 @@ grokdeclarator (const cp_declarator *declarator, "%<auto%> type %qT", type); inlinep = 0; typedef_p = 0; - constexpr_p = 0; consteval_p = 0; concept_p = 0; if (storage_class != sc_static) diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index abeb028..eb2ff33 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -810,6 +810,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) pp_cxx_ws_string (pp, TYPENAME_IS_ENUM_P (t) ? "enum" : TYPENAME_IS_CLASS_P (t) ? "class" + : TYPENAME_IS_UNION_P (t) ? "union" : "typename"); dump_typename (pp, t, flags); break; diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index c8e79f3..6b5a60a 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -9619,6 +9619,8 @@ trees_out::type_node (tree type) tag_type = enum_type; else if (TYPENAME_IS_CLASS_P (type)) tag_type = class_type; + else if (TYPENAME_IS_UNION_P (type)) + tag_type = union_type; u (int (tag_type)); } } diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 239e6f9..8148495 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -16870,7 +16870,11 @@ cp_parser_decomposition_declaration (cp_parser *parser, decl = error_mark_node; } else - prev = decl2; + { + prev = decl2; + DECL_DECLARED_CONSTEXPR_P (decl2) = DECL_DECLARED_CONSTEXPR_P (decl); + DECL_DECLARED_CONSTINIT_P (decl2) = DECL_DECLARED_CONSTINIT_P (decl); + } if (elt_pushed_scope) pop_scope (elt_pushed_scope); } @@ -35924,7 +35928,9 @@ cp_parser_check_class_key (cp_parser *parser, location_t key_loc, return; bool seen_as_union = TREE_CODE (type) == UNION_TYPE; - if (seen_as_union != (class_key == union_type)) + if (class_key != typename_type + && TREE_CODE (type) != TYPENAME_TYPE + && seen_as_union != (class_key == union_type)) { auto_diagnostic_group d; if (permerror (input_location, "%qs tag used in naming %q#T", diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 3362a6f..40ce987 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -17250,13 +17250,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) return error_mark_node; } - /* FIXME: TYPENAME_IS_CLASS_P conflates 'class' vs 'struct' vs 'union' - tags. TYPENAME_TYPE should probably remember the exact tag that - was written. */ + /* FIXME: TYPENAME_IS_CLASS_P conflates 'class' vs 'struct' tags. + TYPENAME_TYPE should probably remember the exact tag that + was written for -Wmismatched-tags. */ enum tag_types tag_type - = TYPENAME_IS_CLASS_P (t) ? class_type - : TYPENAME_IS_ENUM_P (t) ? enum_type - : typename_type; + = (TYPENAME_IS_CLASS_P (t) ? class_type + : TYPENAME_IS_UNION_P (t) ? union_type + : TYPENAME_IS_ENUM_P (t) ? enum_type + : typename_type); tsubst_flags_t tcomplain = complain | tf_keep_type_decl; tcomplain |= tst_ok_flag | qualifying_scope_flag; f = make_typename_type (ctx, f, tag_type, tcomplain); @@ -17278,10 +17279,18 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) else return error_mark_node; } - else if (TYPENAME_IS_CLASS_P (t) && !CLASS_TYPE_P (f)) + else if (TYPENAME_IS_CLASS_P (t) && !NON_UNION_CLASS_TYPE_P (f)) { if (complain & tf_error) - error ("%qT resolves to %qT, which is not a class type", + error ("%qT resolves to %qT, which is not a non-union " + "class type", t, f); + else + return error_mark_node; + } + else if (TYPENAME_IS_UNION_P (t) && !UNION_TYPE_P (f)) + { + if (complain & tf_error) + error ("%qT resolves to %qT, which is not a union type", t, f); else return error_mark_node; diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp3.C b/gcc/testsuite/g++.dg/cpp1z/decomp3.C index a9b23b0..202edc3 100644 --- a/gcc/testsuite/g++.dg/cpp1z/decomp3.C +++ b/gcc/testsuite/g++.dg/cpp1z/decomp3.C @@ -19,7 +19,8 @@ test (A &b, B c) // { dg-error "expected primary-expression before 'decltype'" "" { target c++11_down } .-2 } auto & & && & [ m, n, o ] = b; // { dg-error "multiple ref-qualifiers" } // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 } - constexpr auto [ p ] = c; // { dg-error "structured binding declaration cannot be 'constexpr'" } + constexpr B c2 = { 42 }; + constexpr auto [ p ] = c2; // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } } // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 } friend auto [ q ] = c; // { dg-error "'friend' used outside of class" } // { dg-warning "structured bindings only available with '-std=c..17' or '-std=gnu..17'" "" { target c++14_down } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp26/decomp22.C b/gcc/testsuite/g++.dg/cpp26/decomp22.C new file mode 100644 index 0000000..576a93b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/decomp22.C @@ -0,0 +1,66 @@ +// C++26 P2686R4 - constexpr structured bindings +// { dg-do compile { target c++11 } } +// { dg-options "" } + +namespace std { + template <typename T> struct tuple_size; + template <int, typename> struct tuple_element; +} + +struct A { + int i, j; + template <int I> constexpr const int &get () const { return I == 1 ? j : i; } +}; + +template <> struct std::tuple_size <const A> { static const int value = 3; }; +template <int I> struct std::tuple_element <I, const A> { using type = const int; }; + +constexpr struct B { + int i, j; + long long k, l; +} a[3] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; + +constexpr auto [ b, c, d ] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } +#if __cpp_constinit >= 201907 +constinit auto [ e, f, g ] = a; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif +constexpr auto [ h, i, j, k ] = a[1]; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } +#if __cpp_constinit >= 201907 +constinit auto [ l, m, n, o ] = a[2]; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif +constexpr auto & [ p, q, r ] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } +#if __cpp_constinit >= 201907 +constinit auto & [ s, t, u ] = a; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif +constexpr auto & [ v, w, x, y ] = a[1]; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } +#if __cpp_constinit >= 201907 +constinit auto & [ aa, ab, ac, ad ] = a[2]; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif +static_assert (b.i == 1 && b.l == 4 && c.j == 6 && c.k == 7 && d.i == 9 && d.k == 11, ""); +static_assert (h == 5 && i == 6 && j == 7 && k == 8, ""); +static_assert (p.i == 1 && p.l == 4 && q.j == 6 && q.k == 7 && r.i == 9 && r.k == 11, ""); +static_assert (&p.i == &a[0].i && &p.l == &a[0].l && &q.j == &a[1].j, ""); +static_assert (&q.k == &a[1].k && &r.i == &a[2].i && &r.k == &a[2].k, ""); +static_assert (v == 5 && w == 6 && x == 7 && y == 8, ""); +static_assert (&v == &a[1].i && &w == &a[1].j && &x == &a[1].k && &y == &a[1].l, ""); + +constexpr A z = { 42, -42 }; +constexpr auto [ ae, af, ag ] = z; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } +#if __cpp_constinit >= 201907 +constinit const auto [ ah, ai, aj ] = z; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif +constexpr auto & [ ak, al, am ] = z; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } +#if __cpp_constinit >= 201907 +constinit auto & [ an, ao, ap ] = z; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif +static_assert (ae == 42 && af == -42 && ag == 42, ""); +static_assert (&af == &ae + 1 && &ag == &ae, ""); +static_assert (&ae != &z.i && &af != &z.j && &ag != &z.i, ""); +static_assert (ak == 42 && al == -42 && am == 42, ""); +static_assert (&ak == &z.i && &al == &z.j && &am == &z.i, ""); diff --git a/gcc/testsuite/g++.dg/cpp26/decomp23.C b/gcc/testsuite/g++.dg/cpp26/decomp23.C new file mode 100644 index 0000000..ad2f7e0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/decomp23.C @@ -0,0 +1,77 @@ +// C++26 P2686R4 - constexpr structured bindings +// { dg-do compile { target c++11 } } +// { dg-options "" } + +namespace std { + template <typename T> struct tuple_size; + template <int, typename> struct tuple_element; +} + +struct A { + int i, j; + template <int I> constexpr const int &get () const { return I == 1 ? j : i; } +}; + +template <> struct std::tuple_size <const A> { static const int value = 3; }; +template <int I> struct std::tuple_element <I, const A> { using type = const int; }; + +struct B { + int i, j; + long long k, l; +}; + +void +foo () +{ + static constexpr B a[3] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; + static constexpr auto [ b, c, d ] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 } +#if __cpp_constinit >= 201907 + static constinit auto [ e, f, g ] = a; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif + static constexpr auto [ h, i, j, k ] = a[1]; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 } +#if __cpp_constinit >= 201907 + static constinit auto [ l, m, n, o ] = a[2]; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif + static constexpr auto & [ p, q, r ] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 } +#if __cpp_constinit >= 201907 + static constinit auto & [ s, t, u ] = a; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif + static constexpr auto & [ v, w, x, y ] = a[1]; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 } +#if __cpp_constinit >= 201907 + static constinit auto & [ aa, ab, ac, ad ] = a[2]; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif + static_assert (b.i == 1 && b.l == 4 && c.j == 6 && c.k == 7 && d.i == 9 && d.k == 11, ""); + static_assert (h == 5 && i == 6 && j == 7 && k == 8, ""); + static_assert (p.i == 1 && p.l == 4 && q.j == 6 && q.k == 7 && r.i == 9 && r.k == 11, ""); + static_assert (&p.i == &a[0].i && &p.l == &a[0].l && &q.j == &a[1].j, ""); + static_assert (&q.k == &a[1].k && &r.i == &a[2].i && &r.k == &a[2].k, ""); + static_assert (v == 5 && w == 6 && x == 7 && y == 8, ""); + static_assert (&v == &a[1].i && &w == &a[1].j && &x == &a[1].k && &y == &a[1].l, ""); + + static constexpr A z = { 42, -42 }; + static constexpr auto [ ae, af, ag ] = z; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 } +#if __cpp_constinit >= 201907 + static constinit const auto [ ah, ai, aj ] = z; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif + static constexpr auto & [ ak, al, am ] = z; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 } +#if __cpp_constinit >= 201907 + static constinit auto & [ an, ao, ap ] = z; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif + static_assert (ae == 42 && af == -42 && ag == 42, ""); + static_assert (&af == &ae + 1 && &ag == &ae, ""); + static_assert (&ae != &z.i && &af != &z.j && &ag != &z.i, ""); + static_assert (ak == 42 && al == -42 && am == 42, ""); + static_assert (&ak == &z.i && &al == &z.j && &am == &z.i, ""); +} diff --git a/gcc/testsuite/g++.dg/cpp26/decomp24.C b/gcc/testsuite/g++.dg/cpp26/decomp24.C new file mode 100644 index 0000000..5da1321 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/decomp24.C @@ -0,0 +1,20 @@ +// C++26 P2686R4 - constexpr structured bindings +// { dg-do compile { target c++11 } } +// { dg-options "" } + +struct B { + int i, j; + long long k, l; +}; + +void +foo () +{ + constexpr B a[3] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; + constexpr auto [ b, c, d ] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + constexpr auto [ h, i, j, k ] = a[1]; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + static_assert (b.i == 1 && b.l == 4 && c.j == 6 && c.k == 7 && d.i == 9 && d.k == 11, ""); + static_assert (h == 5 && i == 6 && j == 7 && k == 8, ""); +} diff --git a/gcc/testsuite/g++.dg/cpp26/decomp25.C b/gcc/testsuite/g++.dg/cpp26/decomp25.C new file mode 100644 index 0000000..55559f0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/decomp25.C @@ -0,0 +1,119 @@ +// C++26 P2686R4 - constexpr structured bindings +// { dg-do compile { target c++11 } } +// { dg-options "" } + +namespace std { + template <typename T> struct tuple_size; + template <int, typename> struct tuple_element; +} + +struct A { + int i, j; + template <int I> int &get () { return I == 1 ? j : i; } +}; + +template <> struct std::tuple_size <A> { static const int value = 3; }; +template <int I> struct std::tuple_element <I, A> { using type = int; }; +template <> struct std::tuple_size <const A> { static const int value = 3; }; +template <int I> struct std::tuple_element <I, const A> { using type = int; }; + +struct B { + int i, j; + long long k, l; +} a[3] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; // { dg-message "'a' was not declared 'constexpr'" "" } + +struct C { + int i, j; + template <int I> const int &get () const { return I == 1 ? j : i; } +}; + +template <> struct std::tuple_size <const C> { static const int value = 3; }; +template <int I> struct std::tuple_element <I, const C> { using type = const int; }; + +constexpr auto [ b, c, d ] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-error "the value of 'a' is not usable in a constant expression" "" { target *-*-* } .-2 } +#if __cpp_constinit >= 201907 +constinit auto [ e, f, g ] = a; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } + // { dg-error "'constinit' variable '<structured bindings>' does not have a constant initializer" "" { target c++20 } .-1 } + // { dg-error "the value of 'a' is not usable in a constant expression" "" { target c++20 } .-2 } +#endif +constexpr auto [ h, i, j, k ] = a[1]; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-error "the value of 'a' is not usable in a constant expression" "" { target *-*-* } .-2 } +#if __cpp_constinit >= 201907 +constinit auto [ l, m, n, o ] = a[2]; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } + // { dg-error "'constinit' variable '<structured bindings>' does not have a constant initializer" "" { target c++20 } .-1 } + // { dg-error "the value of 'a' is not usable in a constant expression" "" { target c++20 } .-2 } +#endif +constexpr auto & [ p, q, r ] = a; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } +#if __cpp_constinit >= 201907 +constinit auto & [ s, t, u ] = a; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif +constexpr auto & [ v, w, x, y ] = a[1]; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } +#if __cpp_constinit >= 201907 +constinit auto & [ aa, ab, ac, ad ] = a[2]; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } +#endif + +A z = { 42, -42 }; // { dg-message "'z' was not declared 'constexpr'" "" } +constexpr auto [ ae, af, ag ] = z; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-error "the value of 'z' is not usable in a constant expression" "" { target *-*-* } .-2 } + // { dg-error "passing 'const A' as 'this' argument discards qualifiers" "" { target *-*-* } .-3 } + // { dg-error "call to non-'constexpr' function 'int\\\& A::get\\\(\\\)" "" { target *-*-* } .-4 } +#if __cpp_constinit >= 201907 +constinit const auto [ ah, ai, aj ] = z; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } + // { dg-error "'constinit' variable '<structured bindings>' does not have a constant initializer" "" { target c++20 } .-1 } + // { dg-error "the value of 'z' is not usable in a constant expression" "" { target c++20 } .-2 } + // { dg-error "passing 'const A' as 'this' argument discards qualifiers" "" { target c++20 } .-3 } + // { dg-error "call to non-'constexpr' function 'int\\\& A::get\\\(\\\)" "" { target c++20 } .-4 } + // { dg-error "'constinit' variable 'ah' does not have a constant initializer" "" { target c++20 } .-5 } + // { dg-error "'constinit' variable 'ai' does not have a constant initializer" "" { target c++20 } .-6 } + // { dg-error "'constinit' variable 'aj' does not have a constant initializer" "" { target c++20 } .-7 } +#endif +constexpr auto & [ ak, al, am ] = z; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-error "call to non-'constexpr' function 'int\\\& A::get\\\(\\\)" "" { target *-*-* } .-2 } +#if __cpp_constinit >= 201907 +constinit auto & [ an, ao, ap ] = z; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } + // { dg-error "'constinit' variable 'an' does not have a constant initializer" "" { target c++20 } .-1 } + // { dg-error "'constinit' variable 'ao' does not have a constant initializer" "" { target c++20 } .-2 } + // { dg-error "'constinit' variable 'ap' does not have a constant initializer" "" { target c++20 } .-3 } + // { dg-message "call to non-'constexpr' function 'int\\\& A::get\\\(\\\)" "" { target c++20 } .-4 } +#endif + +constexpr C zz = { 42, -42 }; +constexpr auto [ aq, ar, as ] = zz; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-error "call to non-'constexpr' function 'const int\\\& C::get\\\(\\\) const" "" { target *-*-* } .-2 } +#if __cpp_constinit >= 201907 +constinit const auto [ at, au, av ] = zz; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } + // { dg-error "call to non-'constexpr' function 'const int\\\& C::get\\\(\\\) const" "" { target c++20 } .-1 } + // { dg-error "'constinit' variable 'at' does not have a constant initializer" "" { target c++20 } .-2 } + // { dg-error "'constinit' variable 'au' does not have a constant initializer" "" { target c++20 } .-3 } + // { dg-error "'constinit' variable 'av' does not have a constant initializer" "" { target c++20 } .-4 } +#endif +constexpr auto & [ aw, ax, ay ] = zz; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } + // { dg-error "call to non-'constexpr' function 'const int\\\& C::get\\\(\\\) const" "" { target *-*-* } .-2 } +#if __cpp_constinit >= 201907 +constinit auto & [ az, ba, bb ] = zz; // { dg-warning "'constinit' can be applied to structured binding only with" "" { target { c++20 && c++23_down } } } + // { dg-error "'constinit' variable 'az' does not have a constant initializer" "" { target c++20 } .-1 } + // { dg-error "'constinit' variable 'ba' does not have a constant initializer" "" { target c++20 } .-2 } + // { dg-error "'constinit' variable 'bb' does not have a constant initializer" "" { target c++20 } .-3 } + // { dg-message "call to non-'constexpr' function 'const int\\\& C::get\\\(\\\) const" "" { target c++20 } .-4 } +#endif + +void +foo () +{ +#if __cpp_constinit >= 201907 + constexpr B a[3] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; + constinit auto [ b, c, d ] = a; // { dg-error "'constinit' can only be applied to a variable with static or thread storage duration" "" { target c++20 } } + constinit auto & [ e, f, g ] = a; // { dg-error "'constinit' can only be applied to a variable with static or thread storage duration" "" { target c++20 } } + constinit auto [ h, i, j, k ] = a[1]; // { dg-error "'constinit' can only be applied to a variable with static or thread storage duration" "" { target c++20 } } + constinit auto & [ l, m, n, o ] = a[2]; // { dg-error "'constinit' can only be applied to a variable with static or thread storage duration" "" { target c++20 } } +#endif +} diff --git a/gcc/testsuite/g++.dg/cpp26/decomp9.C b/gcc/testsuite/g++.dg/cpp26/decomp9.C index 5629c4c..ee18b60 100644 --- a/gcc/testsuite/g++.dg/cpp26/decomp9.C +++ b/gcc/testsuite/g++.dg/cpp26/decomp9.C @@ -63,6 +63,7 @@ foo (const S &&s) if (static auto [i, j, k] = t) // { dg-warning "structured bindings in conditions only available with" "" { target c++23_down } } ; // { dg-error "'static' invalid in condition" "" { target *-*-* } .-1 } // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 } - if (constexpr auto [i, j, k] = t) // { dg-warning "structured bindings in conditions only available with" "" { target c++23_down } } - ; // { dg-error "structured binding declaration cannot be 'constexpr'" "" { target *-*-* } .-1 } + constexpr T t2 = { 1, 2, 3 }; + if (constexpr auto [i, j, k] = t2) // { dg-warning "structured bindings in conditions only available with" "" { target c++23_down } } + ; // { dg-warning "structured binding declaration can be 'constexpr' only with" "" { target c++23_down } .-1 } } diff --git a/gcc/testsuite/g++.dg/parse/union1.C b/gcc/testsuite/g++.dg/parse/union1.C new file mode 100644 index 0000000..d567ea3 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/union1.C @@ -0,0 +1,19 @@ +// PR c++/83469 +// { dg-do compile } + +struct S { + union U { int m; }; +}; + +template <typename T> +void +f () +{ + union T::U u; +} + +int +main() +{ + f<S>(); +} diff --git a/gcc/testsuite/g++.dg/parse/union2.C b/gcc/testsuite/g++.dg/parse/union2.C new file mode 100644 index 0000000..cdb1392 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/union2.C @@ -0,0 +1,19 @@ +// PR c++/83469 +// { dg-do compile } + +struct S { + union U { int m; }; +}; + +template <typename T> +void +f () +{ + struct T::U u; // { dg-error "not a non-union class type" } +} + +int +main() +{ + f<S>(); +} diff --git a/gcc/testsuite/g++.dg/parse/union3.C b/gcc/testsuite/g++.dg/parse/union3.C new file mode 100644 index 0000000..61552a4 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/union3.C @@ -0,0 +1,19 @@ +// PR c++/83469 +// { dg-do compile } + +struct S { + struct C { int m; }; +}; + +template <typename T> +void +f () +{ + union T::C u; // { dg-error "not a union type" } +} + +int +main() +{ + f<S>(); +} diff --git a/gcc/testsuite/g++.dg/parse/union4.C b/gcc/testsuite/g++.dg/parse/union4.C new file mode 100644 index 0000000..709f6a4 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/union4.C @@ -0,0 +1,12 @@ +// PR c++/93809 +// { dg-do compile } + +class C { }; +enum E { }; +struct S { }; +union U { }; + +typedef typename ::C C2; +typedef typename ::E E2; +typedef typename ::S S2; +typedef typename ::U U2; diff --git a/gcc/testsuite/g++.dg/parse/union5.C b/gcc/testsuite/g++.dg/parse/union5.C new file mode 100644 index 0000000..18238dd --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/union5.C @@ -0,0 +1,5 @@ +// PR c++/93809 +// { dg-do compile { target c++11 } } + +union U {}; +auto var = new (typename ::U); diff --git a/gcc/testsuite/g++.dg/parse/union6.C b/gcc/testsuite/g++.dg/parse/union6.C new file mode 100644 index 0000000..61b9568 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/union6.C @@ -0,0 +1,5 @@ +// PR c++/93809 +// { dg-do compile } + +typedef union{} U; +typename ::U foo () { return U(); } diff --git a/gcc/testsuite/g++.dg/template/error45.C b/gcc/testsuite/g++.dg/template/error45.C index 064554d..f4c6560 100644 --- a/gcc/testsuite/g++.dg/template/error45.C +++ b/gcc/testsuite/g++.dg/template/error45.C @@ -11,7 +11,7 @@ struct enable_if< true, T > template < typename T > struct enable_if< true, T >::type -f( T x ); // { dg-error "not a class type" } +f( T x ); // { dg-error "not a non-union class type" } void g( void ) diff --git a/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C b/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C index 0eeee34..dcccdca 100644 --- a/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C +++ b/gcc/testsuite/g++.dg/warn/Wredundant-tags-3.C @@ -28,7 +28,7 @@ struct N::S s3; // { dg-warning "-Wredundant-tags" } N::U u1; typename N::U u2; // { dg-bogus "-Wredundant-tags" } - // { dg-bogus "'class' tag used in naming 'union N::U" "pr93809" { xfail *-*-*} .-1 } + // { dg-bogus "'class' tag used in naming 'union N::U" "pr93809" { target *-*-*} .-1 } union N::U u3; // { dg-warning "-Wredundant-tags" } diff --git a/gcc/testsuite/gcc.target/s390/stack-protector-guard-tls-1.c b/gcc/testsuite/gcc.target/s390/stack-protector-guard-tls-1.c new file mode 100644 index 0000000..1efd245 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/stack-protector-guard-tls-1.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fstack-protector-all" } */ +/* { dg-final { scan-assembler-times {\tear\t%r[0-9]+,%a[01]} 8 { target lp64 } } } */ +/* { dg-final { scan-assembler-times {\tsllg\t%r[0-9]+,%r[0-9]+,32} 4 { target lp64 } } } */ +/* { dg-final { scan-assembler-times {\tear\t%r[0-9]+,%a[01]} 3 { target { ! lp64 } } } } */ +/* { dg-final { scan-assembler-times {\tmvc\t160\(8,%r15\),40\(%r[0-9]+\)} 2 { target lp64 } } } */ +/* { dg-final { scan-assembler-times {\tmvc\t100\(4,%r15\),20\(%r[0-9]+\)} 2 { target { ! lp64 } } } } */ +/* { dg-final { scan-assembler-times {\tclc\t160\(8,%r15\),40\(%r[0-9]+\)} 2 { target lp64 } } } */ +/* { dg-final { scan-assembler-times {\tclc\t100\(4,%r15\),20\(%r[0-9]+\)} 2 { target { ! lp64 } } } } */ + +/* Computing the address of the thread pointer on s390 involves multiple + instructions and therefore bears the risk that the address of the canary or + intermediate values of it are spilled and reloaded. Therefore, as a + precaution compute the address always twice, i.e., one time for the prologue + and one time for the epilogue. */ + +void test_0 (void) { } + +void test_1 (void) +{ + __asm__ __volatile ("" ::: + "r0", + "r1", + "r2", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", +#ifndef __PIC__ + "r12", +#endif + "r13", + "r14"); +} diff --git a/gcc/testsuite/gcc.target/xtensa/BGEUI-BLTUI-32k-64k.c b/gcc/testsuite/gcc.target/xtensa/BGEUI-BLTUI-32k-64k.c new file mode 100644 index 0000000..05873b8 --- /dev/null +++ b/gcc/testsuite/gcc.target/xtensa/BGEUI-BLTUI-32k-64k.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern void foo(void); + +void BGEUI_test(unsigned int a) +{ + if (a < 32768U) + foo(); +} + +void BLTUI_test(unsigned int a) +{ + if (a >= 65536U) + foo(); +} + +/* { dg-final { scan-assembler-times "bgeui" 1 } } */ +/* { dg-final { scan-assembler-times "bltui" 1 } } */ |