aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ada/sem_ch7.adb104
-rw-r--r--gcc/c-family/c-opts.cc10
-rw-r--r--gcc/c-family/c.opt4
-rw-r--r--gcc/c-family/c.opt.urls3
-rw-r--r--gcc/cp/call.cc45
-rw-r--r--gcc/cp/constexpr.cc10
-rw-r--r--gcc/cp/cp-gimplify.cc69
-rw-r--r--gcc/cp/cp-tree.h9
-rw-r--r--gcc/cp/decl.cc529
-rw-r--r--gcc/cp/module.cc112
-rw-r--r--gcc/cp/name-lookup.cc58
-rw-r--r--gcc/cp/name-lookup.h16
-rw-r--r--gcc/cp/parser.cc9
-rw-r--r--gcc/cp/pt.cc7
-rw-r--r--gcc/cp/semantics.cc8
-rw-r--r--gcc/cp/tree.cc19
-rw-r--r--gcc/doc/invoke.texi58
-rw-r--r--gcc/flag-types.h3
-rw-r--r--gcc/gimplify.cc173
-rw-r--r--gcc/ipa-split.cc9
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/invalid-shift-1.c4
-rw-r--r--gcc/testsuite/c-c++-common/goacc-gomp/nesting-1.c11
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-decompose-2.c3
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr100400-1-1.c1
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr100400-1-3.c1
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-1.c1
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-3.c1
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-4.c1
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104132-1.c1
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104133-1.c1
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104774-1.c1
-rw-r--r--gcc/testsuite/c-c++-common/goacc/mdc-1.c1
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/vla-1.c2
-rw-r--r--gcc/testsuite/c-c++-common/uninit-17.c4
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-value-2.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template18.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/vla-initlist1.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp26/attr-indeterminate1.C154
-rw-r--r--gcc/testsuite/g++.dg/cpp26/attr-indeterminate2.C39
-rw-r--r--gcc/testsuite/g++.dg/cpp26/attr-indeterminate3.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp26/attr-indeterminate4.C36
-rw-r--r--gcc/testsuite/g++.dg/cpp26/erroneous1.C61
-rw-r--r--gcc/testsuite/g++.dg/cpp26/erroneous2.C234
-rw-r--r--gcc/testsuite/g++.dg/cpp26/erroneous3.C158
-rw-r--r--gcc/testsuite/g++.dg/cpp26/erroneous4.C37
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constexpr-new28.C45
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constexpr-new29.C30
-rw-r--r--gcc/testsuite/g++.dg/modules/adl-6_c.C5
-rw-r--r--gcc/testsuite/g++.dg/modules/internal-14_c.C2
-rw-r--r--gcc/testsuite/g++.dg/modules/internal-15_a.C28
-rw-r--r--gcc/testsuite/g++.dg/modules/internal-15_b.C13
-rw-r--r--gcc/testsuite/g++.dg/opt/store-merging-1.C2
-rw-r--r--gcc/testsuite/g++.dg/parse/auto-struct-param.C4
-rw-r--r--gcc/testsuite/g++.dg/uninit-pred-loop-1_b.C2
-rw-r--r--gcc/testsuite/g++.dg/warn/Warray-bounds-20.C12
-rw-r--r--gcc/testsuite/g++.dg/warn/Wuninitialized-13.C4
-rw-r--r--gcc/testsuite/gnat.dg/use_type1.adb16
-rw-r--r--gcc/testsuite/gnat.dg/use_type2.adb15
-rw-r--r--gcc/tree-ssa-uninit.cc25
-rw-r--r--gcc/tree.h13
60 files changed, 2083 insertions, 179 deletions
diff --git a/gcc/ada/sem_ch7.adb b/gcc/ada/sem_ch7.adb
index 42abc89..1d838e2 100644
--- a/gcc/ada/sem_ch7.adb
+++ b/gcc/ada/sem_ch7.adb
@@ -2521,11 +2521,13 @@ package body Sem_Ch7 is
and then Scope (Full_View (Id)) = Scope (Id)
and then Ekind (Full_View (Id)) /= E_Incomplete_Type
then
+ Full := Full_View (Id);
+
-- If there is a use-type clause on the private type, set the full
-- view accordingly.
- Set_In_Use (Full_View (Id), In_Use (Id));
- Full := Full_View (Id);
+ Set_In_Use (Full, In_Use (Id));
+ Set_Current_Use_Clause (Full, Current_Use_Clause (Id));
if Is_Private_Base_Type (Full)
and then Has_Private_Declaration (Full)
@@ -2893,7 +2895,12 @@ package body Sem_Ch7 is
-- When compiling a child unit this needs to be done recursively.
function Type_In_Use (T : Entity_Id) return Boolean;
- -- Check whether type or base type appear in an active use_type clause
+ -- Check whether type T is declared in P and appears in an active
+ -- use_type clause.
+
+ function Type_Of_Primitive_In_Use_All (Id : Entity_Id) return Boolean;
+ -- Check whether the profile of primitive subprogram Id mentions a type
+ -- declared in P that appears in an active use-all-type clause.
------------------------------
-- Preserve_Full_Attributes --
@@ -3058,11 +3065,86 @@ package body Sem_Ch7 is
-----------------
function Type_In_Use (T : Entity_Id) return Boolean is
+ BT : constant Entity_Id := Base_Type (T);
begin
- return Scope (Base_Type (T)) = P
- and then (In_Use (T) or else In_Use (Base_Type (T)));
+ return Scope (BT) = P and then (In_Use (T) or else In_Use (BT));
end Type_In_Use;
+ ----------------------------------
+ -- Type_Of_Primitive_In_Use_All --
+ ----------------------------------
+
+ function Type_Of_Primitive_In_Use_All (Id : Entity_Id) return Boolean is
+ function Type_In_Use_All (T : Entity_Id) return Boolean;
+ -- Check whether type T is declared in P and appears in an active
+ -- use-all-type clause.
+
+ ---------------------
+ -- Type_In_Use_All --
+ ---------------------
+
+ function Type_In_Use_All (T : Entity_Id) return Boolean is
+ begin
+ return Type_In_Use (T)
+ and then Nkind (Current_Use_Clause (T)) = N_Use_Type_Clause
+ and then All_Present (Current_Use_Clause (T));
+ end Type_In_Use_All;
+
+ -- Local variables
+
+ F : Node_Id;
+
+ -- Start of processing for Type_Of_Primitive_In_Use_All
+
+ begin
+ -- The use-all-type clauses were introduced in Ada 2005
+
+ if Ada_Version <= Ada_95 then
+ return False;
+ end if;
+
+ -- For enumeration literals, check type
+
+ if Ekind (Id) = E_Enumeration_Literal then
+ return Type_In_Use_All (Etype (Id));
+ end if;
+
+ -- For functions, check return type
+
+ if Ekind (Id) = E_Function then
+ declare
+ Typ : constant Entity_Id :=
+ (if Ekind (Etype (Id)) = E_Anonymous_Access_Type
+ then Designated_Type (Etype (Id))
+ else Etype (Id));
+ begin
+ if Type_In_Use_All (Typ) then
+ return True;
+ end if;
+ end;
+ end if;
+
+ -- For all subprograms, check formals
+
+ F := First_Formal (Id);
+ while Present (F) loop
+ declare
+ Typ : constant Entity_Id :=
+ (if Ekind (Etype (F)) = E_Anonymous_Access_Type
+ then Designated_Type (Etype (F))
+ else Etype (F));
+ begin
+ if Type_In_Use_All (Typ) then
+ return True;
+ end if;
+ end;
+
+ Next_Formal (F);
+ end loop;
+
+ return False;
+ end Type_Of_Primitive_In_Use_All;
+
-- Start of processing for Uninstall_Declarations
begin
@@ -3120,13 +3202,13 @@ package body Sem_Ch7 is
elsif No (Etype (Id)) and then Serious_Errors_Detected /= 0 then
null;
- -- We need to avoid incorrectly marking enumeration literals as
- -- non-visible when a visible use-all-type clause is in effect.
+ -- RM 8.4(8.1/3): Each primitive subprogram of T, including each
+ -- enumeration literal (if any), is potentially use-visible if T
+ -- is named in an active use-all-type clause.
- elsif Type_In_Use (Etype (Id))
- and then Nkind (Current_Use_Clause (Etype (Id))) =
- N_Use_Type_Clause
- and then All_Present (Current_Use_Clause (Etype (Id)))
+ elsif (Ekind (Id) = E_Enumeration_Literal
+ or else (Is_Subprogram (Id) and then Is_Primitive (Id)))
+ and then Type_Of_Primitive_In_Use_All (Id)
then
null;
diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
index 0ec30e8..54e397c 100644
--- a/gcc/c-family/c-opts.cc
+++ b/gcc/c-family/c-opts.cc
@@ -913,6 +913,16 @@ c_common_post_options (const char **pfilename)
else
flag_permitted_flt_eval_methods = PERMITTED_FLT_EVAL_METHODS_C11;
+ if (cxx_dialect >= cxx26)
+ SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+ flag_auto_var_init, AUTO_INIT_CXX26);
+
+ /* The -Wtrivial-auto-var-init warning is useless for C++, where we always
+ add .DEFERRED_INIT calls when some (vacuous) initializers are bypassed
+ through jumps from switch condition to case/default label. */
+ if (c_dialect_cxx ())
+ warn_trivial_auto_var_init = 0;
+
/* C23 Annex F does not permit certain built-in functions to raise
"inexact". */
if (flag_isoc23)
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 4fd8770..abe0aa6 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -761,6 +761,10 @@ Wexpansion-to-defined
C ObjC C++ ObjC++ CPP(warn_expansion_to_defined) CppReason(CPP_W_EXPANSION_TO_DEFINED) Var(cpp_warn_expansion_to_defined) Init(0) Warning EnabledBy(Wextra || Wpedantic)
Warn if \"defined\" is used outside #if.
+Wexternal-tu-local
+C++ ObjC++ Var(warn_tu_local) Warning Init(1)
+Warn about naming a TU-local entity declared in another translation unit.
+
Wextra
C ObjC C++ ObjC++ Warning
; in common.opt
diff --git a/gcc/c-family/c.opt.urls b/gcc/c-family/c.opt.urls
index 6c01a7d..399f9f8 100644
--- a/gcc/c-family/c.opt.urls
+++ b/gcc/c-family/c.opt.urls
@@ -376,6 +376,9 @@ UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wexceptions)
Wexpansion-to-defined
UrlSuffix(gcc/Warning-Options.html#index-Wexpansion-to-defined)
+Wexternal-tu-local
+UrlSuffix(gcc/C_002b_002b-Dialect-Options.html#index-Wexternal-tu-local)
+
Wextra
UrlSuffix(gcc/Warning-Options.html#index-Wextra) LangUrlSuffix_D(gdc/Warnings.html#index-Wextra) LangUrlSuffix_Fortran(gfortran/Error-and-Warning-Options.html#index-Wextra)
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 97c8a48..77dfa7d 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -10488,6 +10488,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
unsigned int arg_index = 0;
int conv_index = 0;
int param_index = 0;
+ tree parmd = DECL_ARGUMENTS (fn);
auto consume_object_arg = [&arg_index, &first_arg, args]()
{
@@ -10505,6 +10506,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
tree object_arg = consume_object_arg ();
argarray[argarray_size++] = build_this (object_arg);
parm = TREE_CHAIN (parm);
+ if (parmd)
+ parmd = DECL_CHAIN (parmd);
/* We should never try to call the abstract constructor. */
gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (fn));
@@ -10513,6 +10516,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
argarray[argarray_size++] = (*args)[arg_index];
++arg_index;
parm = TREE_CHAIN (parm);
+ if (parmd)
+ parmd = DECL_CHAIN (parmd);
}
}
/* Bypass access control for 'this' parameter. */
@@ -10600,6 +10605,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
argarray[argarray_size++] = converted_arg;
parm = TREE_CHAIN (parm);
+ if (parmd)
+ parmd = DECL_CHAIN (parmd);
}
auto handle_arg = [fn, flags](tree type,
@@ -10623,6 +10630,27 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
return val;
};
+ auto handle_indeterminate_arg = [](tree parmd, tree val)
+ {
+ if (parmd
+ && lookup_attribute (NULL, "indeterminate", DECL_ATTRIBUTES (parmd)))
+ {
+ STRIP_NOPS (val);
+ if (TREE_CODE (val) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (val, 0)) == TARGET_EXPR)
+ {
+ val = TARGET_EXPR_SLOT (TREE_OPERAND (val, 0));
+ if (auto_var_p (val) && DECL_ARTIFICIAL (val))
+ {
+ tree id = get_identifier ("indeterminate");
+ DECL_ATTRIBUTES (val)
+ = tree_cons (build_tree_list (NULL_TREE, id), NULL_TREE,
+ DECL_ATTRIBUTES (val));
+ }
+ }
+ }
+ };
+
if (DECL_XOBJ_MEMBER_FUNCTION_P (fn))
{
gcc_assert (cand->num_convs > 0);
@@ -10636,8 +10664,13 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
if (val == error_mark_node)
return error_mark_node;
else
- argarray[argarray_size++] = val;
+ {
+ argarray[argarray_size++] = val;
+ handle_indeterminate_arg (parmd, val);
+ }
parm = TREE_CHAIN (parm);
+ if (parmd)
+ parmd = DECL_CHAIN (parmd);
}
gcc_assert (first_arg == NULL_TREE);
@@ -10683,7 +10716,12 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
if (val == error_mark_node)
return error_mark_node;
else
- argarray[argarray_size++] = val;
+ {
+ argarray[argarray_size++] = val;
+ handle_indeterminate_arg (parmd, val);
+ }
+ if (parmd)
+ parmd = DECL_CHAIN (parmd);
}
/* Default arguments */
@@ -10699,6 +10737,9 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
if (val == error_mark_node)
return error_mark_node;
argarray[argarray_size++] = val;
+ handle_indeterminate_arg (parmd, val);
+ if (parmd)
+ parmd = DECL_CHAIN (parmd);
}
/* Ellipsis */
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 558ef6e..016e3db 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3009,6 +3009,9 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
vc_prvalue, non_constant_p,
overflow_p, jump_target);
+ case IFN_DEFERRED_INIT:
+ return build_clobber (TREE_TYPE (t), CLOBBER_OBJECT_BEGIN);
+
case IFN_VEC_CONVERT:
{
tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0),
@@ -7498,6 +7501,13 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
bool preeval = SCALAR_TYPE_P (type) || TREE_CODE (t) == MODIFY_EXPR;
if (preeval && !TREE_CLOBBER_P (init))
{
+ /* Ignore var = .DEFERRED_INIT (); for now, until PR121965 is fixed. */
+ if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && TREE_CODE (init) == CALL_EXPR
+ && CALL_EXPR_FN (init) == NULL_TREE
+ && CALL_EXPR_IFN (init) == IFN_DEFERRED_INIT)
+ return void_node;
+
/* Evaluate the value to be stored without knowing what object it will be
stored in, so that any side-effects happen first. */
if (!SCALAR_TYPE_P (type))
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 2111dca..1662336 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -200,6 +200,33 @@ genericize_if_stmt (tree *stmt_p)
}
}
+ if (IF_STMT_VACUOUS_INIT_P (stmt))
+ {
+ gcc_checking_assert (integer_zerop (cond));
+ gcc_checking_assert (!else_ || !TREE_SIDE_EFFECTS (else_));
+ tree lab = create_artificial_label (UNKNOWN_LOCATION);
+ VACUOUS_INIT_LABEL_P (lab) = 1;
+ tree goto_expr = build_stmt (UNKNOWN_LOCATION, GOTO_EXPR, lab);
+ tree label_expr = build_stmt (UNKNOWN_LOCATION, LABEL_EXPR, lab);
+ if (TREE_CODE (then_) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator i = tsi_start (then_);
+ tsi_link_before (&i, goto_expr, TSI_CONTINUE_LINKING);
+ i = tsi_last (then_);
+ tsi_link_after (&i, label_expr, TSI_CONTINUE_LINKING);
+ stmt = then_;
+ }
+ else
+ {
+ stmt = NULL_TREE;
+ append_to_statement_list (goto_expr, &stmt);
+ append_to_statement_list (then_, &stmt);
+ append_to_statement_list (label_expr, &stmt);
+ }
+ *stmt_p = stmt;
+ return;
+ }
+
if (!then_)
then_ = build_empty_stmt (locus);
if (!else_)
@@ -603,6 +630,38 @@ cp_gimplify_arg (tree *arg_p, gimple_seq *pre_p, location_t call_location,
}
+/* Emit a decl = {CLOBBER(bob)}; stmt before DECL_EXPR or first
+ TARGET_EXPR gimplification for -flifetime-dse=2. */
+
+static void
+maybe_emit_clobber_object_begin (tree decl, gimple_seq *pre_p)
+{
+ if (VAR_P (decl)
+ && auto_var_p (decl)
+ && TREE_TYPE (decl) != error_mark_node
+ && DECL_NONTRIVIALLY_INITIALIZED_P (decl)
+ /* Don't do it if it is fully initialized. */
+ && DECL_INITIAL (decl) == NULL_TREE
+ && !DECL_HAS_VALUE_EXPR_P (decl)
+ && !OPAQUE_TYPE_P (TREE_TYPE (decl))
+ /* Nor going to have decl = .DEFERRED_INIT (...); added. */
+ && (flag_auto_var_init == AUTO_INIT_UNINITIALIZED
+ || lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl))
+ || lookup_attribute ("indeterminate", DECL_ATTRIBUTES (decl))))
+ {
+ tree eltype = strip_array_types (TREE_TYPE (decl));
+ if (RECORD_OR_UNION_TYPE_P (eltype)
+ && !is_empty_class (eltype))
+ {
+ tree clobber
+ = build_clobber (TREE_TYPE (decl), CLOBBER_OBJECT_BEGIN);
+ gimple *g = gimple_build_assign (decl, clobber);
+ gimple_set_location (g, DECL_SOURCE_LOCATION (decl));
+ gimple_seq_add_stmt_without_update (pre_p, g);
+ }
+ }
+}
+
/* Do C++-specific gimplification. Args are as for gimplify_expr. */
int
@@ -918,6 +977,10 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
on the rhs of an assignment, as in constexpr-aggr1.C. */
gcc_checking_assert (!TARGET_EXPR_ELIDING_P (*expr_p)
|| !TREE_ADDRESSABLE (TREE_TYPE (*expr_p)));
+ if (flag_lifetime_dse > 1
+ && TARGET_EXPR_INITIAL (*expr_p)
+ && VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (*expr_p))))
+ maybe_emit_clobber_object_begin (TARGET_EXPR_SLOT (*expr_p), pre_p);
ret = GS_UNHANDLED;
break;
@@ -929,6 +992,12 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
ret = GS_OK;
break;
+ case DECL_EXPR:
+ if (flag_lifetime_dse > 1)
+ maybe_emit_clobber_object_begin (DECL_EXPR_DECL (*expr_p), pre_p);
+ ret = GS_UNHANDLED;
+ break;
+
case RETURN_EXPR:
if (TREE_OPERAND (*expr_p, 0)
&& (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == INIT_EXPR
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6ee945f..5f8dfad 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -510,6 +510,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
PACK_EXPANSION_FORCE_EXTRA_ARGS_P (in *_PACK_EXPANSION)
LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR)
TARGET_EXPR_ELIDING_P (in TARGET_EXPR)
+ IF_STMT_VACUOUS_INIT_P (IF_STMT)
contract_semantic (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT)
TYPENAME_IS_UNION_P (in TYPENAME_TYPE)
4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
@@ -1856,7 +1857,8 @@ struct GTY(()) tree_tu_local_entity {
location_t loc;
};
-/* The name of a translation-unit-local entity. */
+/* The human-readable name of a translation-unit-local entity as
+ an IDENTIFIER_NODE. */
#define TU_LOCAL_ENTITY_NAME(NODE) \
(((struct tree_tu_local_entity *)TU_LOCAL_ENTITY_CHECK (NODE))->name)
@@ -5686,6 +5688,9 @@ decl_template_parm_check (const_tree t, const char *f, int l, const char *fn)
#define IF_SCOPE(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 3)
#define IF_STMT_CONSTEXPR_P(NODE) TREE_LANG_FLAG_0 (IF_STMT_CHECK (NODE))
#define IF_STMT_CONSTEVAL_P(NODE) TREE_LANG_FLAG_2 (IF_STMT_CHECK (NODE))
+/* True on artificial if (0) around .DEFERRED_INIT calls added for
+ !!flag_auto_var_init. */
+#define IF_STMT_VACUOUS_INIT_P(NODE) TREE_LANG_FLAG_3 (IF_STMT_CHECK (NODE))
/* Like PACK_EXPANSION_EXTRA_ARGS, for constexpr if. IF_SCOPE is used while
building an IF_STMT; IF_STMT_EXTRA_ARGS is used after it is complete. */
@@ -7279,7 +7284,7 @@ extern tree duplicate_decls (tree, tree,
extern void mark_label_addressed (tree);
extern tree declare_local_label (tree);
extern tree define_label (location_t, tree);
-extern void check_goto (tree);
+extern void check_goto (tree *);
extern bool check_omp_return (void);
extern tree make_typename_type (tree, tree, enum tag_types, tsubst_flags_t);
extern tree build_typename_type (tree, tree, tree, tag_types);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 7927b43..885be3b 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -76,6 +76,7 @@ enum bad_spec_place {
static const char *redeclaration_error_message (tree, tree);
static bool decl_jump_unsafe (tree);
+static bool decl_instrument_init_bypass_p (tree);
static void require_complete_types_for_parms (tree);
static tree grok_reference_init (tree, tree, tree, int);
static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *,
@@ -173,6 +174,25 @@ vec<tree, va_gc> *static_decls;
/* vector of keyed classes. */
vec<tree, va_gc> *keyed_classes;
+/* Used in the direct_goto vector of named_label_use_entry for
+ addresses of the LABEL_DECLs within GOTO_EXPR or asm goto
+ for forward jumps. */
+
+struct GTY(()) named_label_fwd_direct_goto {
+ tree *GTY((skip)) direct_goto;
+};
+
+/* Used in the direct_goto vector of named_label_use_entry for
+ addresses of the LABEL_DECLs within GOTO_EXPR or asm goto
+ for backward jumps. */
+
+struct GTY(()) named_label_bck_direct_goto {
+ tree *GTY((skip)) direct_goto;
+ /* Number of the decl_instrument_init_bypass_p decls in bad_decls vector
+ at the time this backward goto has been seen. */
+ unsigned n_bad_decls;
+};
+
/* Used only for jumps to as-yet undefined labels, since jumps to
defined labels can have their validity checked immediately. */
@@ -188,7 +208,11 @@ struct GTY((chain_next ("%h.next"))) named_label_use_entry {
tree names_in_scope;
/* If the use is a possible destination of a computed goto, a vec of decls
that aren't destroyed, filled in by poplevel_named_label_1. */
- vec<tree,va_gc> *computed_goto;
+ vec<tree, va_gc> *computed_goto;
+ /* If the use is a destination of normal goto, a vec of addresses of
+ LABEL_DECLs that might need changing for !!flag_auto_var_init
+ forward jumps across vacuous initializers. */
+ vec<named_label_fwd_direct_goto, va_gc> *direct_goto;
/* The location of the goto, for error reporting. */
location_t o_goto_locus;
/* True if an OpenMP structured block scope has been closed since
@@ -226,20 +250,29 @@ struct GTY((for_user)) named_label_entry {
/* A list of uses of the label, before the label is defined. */
named_label_use_entry *uses;
- /* True if we've seen &&label. Appalently we can't use TREE_ADDRESSABLE for
+ /* If the use is a destination of normal goto, a vec of addresses of
+ LABEL_DECLs that might need changing for !!flag_auto_var_init
+ backward jumps across vacuous initializers. */
+ vec<named_label_bck_direct_goto, va_gc> *direct_goto;
+
+ /* True if we've seen &&label. Apparently we can't use TREE_ADDRESSABLE for
this, it has a more specific meaning for LABEL_DECL. */
- bool addressed;
+ bool addressed : 1;
/* The following bits are set after the label is defined, and are
updated as scopes are popped. They indicate that a jump to the
label will illegally enter a scope of the given flavor. */
- bool in_try_scope;
- bool in_catch_scope;
- bool in_omp_scope;
- bool in_transaction_scope;
- bool in_constexpr_if;
- bool in_consteval_if;
- bool in_stmt_expr;
+ bool in_try_scope : 1;
+ bool in_catch_scope : 1;
+ bool in_omp_scope : 1;
+ bool in_transaction_scope : 1;
+ bool in_constexpr_if : 1;
+ bool in_consteval_if : 1;
+ bool in_stmt_expr : 1;
+
+ /* True if bad_decls chain contains any decl_jump_unsafe decls
+ (rather than just decl_instrument_init_bypass_p). */
+ bool has_bad_decls : 1;
};
#define named_labels cp_function_chain->x_named_labels
@@ -403,6 +436,69 @@ sort_labels (const void *a, const void *b)
return DECL_UID (label1) > DECL_UID (label2) ? -1 : +1;
}
+static void adjust_backward_goto (named_label_entry *, tree_stmt_iterator);
+static named_label_entry *lookup_label_1 (tree, bool);
+
+/* Helper of pop_labels, called through cp_walk_tree. Adjust
+ LABEL_EXPRs of named labels, if they are targets of backwards
+ gotos jumping across vacuous initialization for
+ !!flag_auto_var_init. */
+
+static tree
+adjust_backward_gotos (tree *tp, int *walk_subtrees, void *data)
+{
+ tree t = *tp;
+ switch (TREE_CODE (t))
+ {
+ case LABEL_EXPR:
+ /* In rare cases LABEL_EXPR can appear as the only substatement
+ of some other statement, e.g. if body etc. In that case, we know
+ there can't be an older if (0) wrapper with artificial initializers
+ before it. Replace the LABEL_EXPR statement with a STATEMENT_LIST
+ and insert the LABEL_EXPR into it, later on if (0) will be added
+ before that. */
+ if (DECL_NAME (LABEL_EXPR_LABEL (t)))
+ {
+ named_label_entry *ent
+ = lookup_label_1 (DECL_NAME (LABEL_EXPR_LABEL (t)), false);
+ if (ent->direct_goto)
+ {
+ *tp = alloc_stmt_list ();
+ append_to_statement_list_force (t, tp);
+ adjust_backward_goto (ent, tsi_last (*tp));
+ }
+ }
+ *walk_subtrees = 0;
+ break;
+ case STATEMENT_LIST:
+ {
+ tree_stmt_iterator i;
+ *walk_subtrees = 0;
+ /* In the common case, LABEL_EXPRs appear inside of a STATEMENT_LIST.
+ In that case pass the stmt iterator to adjust_backward_goto, so
+ that it can insert if (0) wrapper artificial initializers before
+ it or reuse the existing ones. */
+ for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
+ if (TREE_CODE (tsi_stmt (i)) != LABEL_EXPR)
+ cp_walk_tree (tsi_stmt_ptr (i), adjust_backward_gotos,
+ data, (hash_set<tree> *) data);
+ else if (DECL_NAME (LABEL_EXPR_LABEL (tsi_stmt (i))))
+ {
+ named_label_entry *ent
+ = lookup_label_1 (DECL_NAME (LABEL_EXPR_LABEL (tsi_stmt (i))),
+ false);
+ if (ent->direct_goto)
+ adjust_backward_goto (ent, i);
+ }
+ break;
+ }
+ default:
+ if (TYPE_P (t))
+ *walk_subtrees = 0;
+ }
+ return NULL_TREE;
+}
+
/* At the end of a function, all labels declared within the function
go out of scope. BLOCK is the top-level block for the
function. */
@@ -420,8 +516,23 @@ pop_labels (tree block)
table implementation changes. */
auto_vec<tree, 32> labels (named_labels->elements ());
hash_table<named_label_hash>::iterator end (named_labels->end ());
- for (hash_table<named_label_hash>::iterator iter
- (named_labels->begin ()); iter != end; ++iter)
+
+ if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
+ {
+ for (decltype (end) iter (named_labels->begin ()); iter != end; ++iter)
+ {
+ named_label_entry *ent = *iter;
+ if (ent->direct_goto)
+ {
+ hash_set<tree> pset;
+ cp_walk_tree (&DECL_SAVED_TREE (current_function_decl),
+ adjust_backward_gotos, &pset, &pset);
+ break;
+ }
+ }
+ }
+
+ for (decltype (end) iter (named_labels->begin ()); iter != end; ++iter)
{
named_label_entry *ent = *iter;
@@ -551,6 +662,11 @@ poplevel_named_label_1 (named_label_entry **slot, cp_binding_level *bl)
? DECL_CHAIN (decl)
: TREE_CHAIN (decl)))
if (decl_jump_unsafe (decl))
+ {
+ vec_safe_push (ent->bad_decls, decl);
+ ent->has_bad_decls = true;
+ }
+ else if (decl_instrument_init_bypass_p (decl))
vec_safe_push (ent->bad_decls, decl);
ent->binding_level = obl;
@@ -2941,6 +3057,19 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
{
DECL_ATTRIBUTES (newarg)
= (*targetm.merge_decl_attributes) (oldarg, newarg);
+ if (lookup_attribute (NULL, "indeterminate",
+ DECL_ATTRIBUTES (newarg))
+ && !lookup_attribute (NULL, "indeterminate",
+ DECL_ATTRIBUTES (oldarg)))
+ {
+ auto_diagnostic_group d;
+ error_at (DECL_SOURCE_LOCATION (newarg),
+ "%<indeterminate%> attribute not specified "
+ "for parameter %qD on the first declaration of "
+ "its function", newarg);
+ inform (DECL_SOURCE_LOCATION (oldarg),
+ "earlier declaration");
+ }
DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg);
}
@@ -3744,6 +3873,259 @@ decl_jump_unsafe (tree decl)
|| variably_modified_type_p (type, NULL_TREE)));
}
+/* Returns true if decl is an automatic variable with vacuous initialization
+ except when it is [[indeterminate]] or [[gnu::uninitialized]].
+ Jumps across such initialization need to be instrumented for
+ !!flag_auto_var_init. */
+
+static bool
+decl_instrument_init_bypass_p (tree decl)
+{
+ tree type = TREE_TYPE (decl);
+
+ return (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && type != error_mark_node
+ && VAR_P (decl)
+ && !TREE_STATIC (decl)
+ && !DECL_EXTERNAL (decl)
+ && !(DECL_NONTRIVIALLY_INITIALIZED_P (decl)
+ || variably_modified_type_p (type, NULL_TREE))
+ && !lookup_attribute (NULL, "indeterminate", DECL_ATTRIBUTES (decl))
+ && !lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl))
+ && !DECL_HAS_VALUE_EXPR_P (decl));
+}
+
+/* Build .DEFERRED_INIT call for DECL. */
+
+static tree
+build_deferred_init_call (tree decl)
+{
+ tree decl_size_arg = TYPE_SIZE_UNIT (TREE_TYPE (decl));
+ tree init_type_arg = build_int_cst (integer_type_node,
+ (int) flag_auto_var_init);
+ location_t loc = DECL_SOURCE_LOCATION (decl);
+ tree decl_name;
+
+ if (DECL_NAME (decl))
+ decl_name = build_string_literal (DECL_NAME (decl));
+ else
+ {
+ char decl_name_anonymous[3 + (HOST_BITS_PER_INT + 2) / 3];
+ sprintf (decl_name_anonymous, "D.%u", DECL_UID (decl));
+ decl_name = build_string_literal (decl_name_anonymous);
+ }
+
+ tree call = build_call_expr_internal_loc (loc, IFN_DEFERRED_INIT,
+ TREE_TYPE (decl), 3,
+ decl_size_arg, init_type_arg,
+ decl_name);
+ tree ret = build2_loc (loc, MODIFY_EXPR, void_type_node, decl, call);
+ return build_stmt (loc, EXPR_STMT, ret);
+}
+
+/* Emit before ITER (and any labels/case labels before it) code like
+ if (0)
+ {
+ l1:
+ v4 = .DEFERRED_INIT (sizeof (v4), ?, "v4");
+ v3 = .DEFERRED_INIT (sizeof (v3), ?, "v3");
+ v2 = .DEFERRED_INIT (sizeof (v2), ?, "v2");
+ v1 = .DEFERRED_INIT (sizeof (v1), ?, "v1");
+ }
+ and return l1 label, or if it already exists, assert it has the
+ .DEFERRED_INIT calls for the right decls in the right order and
+ amend it, either by adding extra labels in between or further
+ ,DEFERRED_INIT calls before the first label and extra label before
+ that. If CASE_LABEL is non-NULL, emit that CASE_LABEL_EXPR instead
+ of adding a label. DECLS points to an array of NDECLS VAR_DECLs
+ which should be initialized. */
+
+static tree
+maybe_add_deferred_init_calls (tree_stmt_iterator iter, tree case_label,
+ tree *decls, unsigned ndecls)
+{
+ tree lab = NULL_TREE;
+ for (; !tsi_end_p (iter); tsi_prev (&iter))
+ {
+ switch (TREE_CODE (tsi_stmt (iter)))
+ {
+ case LABEL_EXPR:
+ case CASE_LABEL_EXPR:
+ case DEBUG_BEGIN_STMT:
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ if (!tsi_end_p (iter)
+ && TREE_CODE (tsi_stmt (iter)) == IF_STMT
+ && IF_STMT_VACUOUS_INIT_P (tsi_stmt (iter)))
+ {
+ /* Found IF_STMT added for this or some adjacent
+ LABEL_EXPR/CASE_LABEL_EXPR by an earlier call to this function.
+ The decls are ordered so that we can always reuse it. Sometimes
+ by no modifications at all and just returning the right label
+ which was added already before, sometimes by adding a label in
+ between two previously added .DEFERRED_INIT calls and sometimes
+ by adding extra statements (.DEFERRED_INIT calls and LABEL_EXPR
+ before that) before the statements in IF_STMT body. */
+ tree then_clause = THEN_CLAUSE (tsi_stmt (iter));
+ iter = tsi_last (then_clause);
+ bool add = false;
+ for (unsigned int i = 0; i < ndecls; ++i)
+ {
+ tree decl = decls[i];
+ if (!add)
+ {
+ /* Skip over labels/case labels after .DEFERRED_INIT for the
+ DECL we are looking for. */
+ while (!tsi_end_p (iter)
+ && (TREE_CODE (tsi_stmt (iter)) == LABEL_EXPR
+ || (TREE_CODE (tsi_stmt (iter)) == CASE_LABEL_EXPR
+ && !case_label)))
+ tsi_prev (&iter);
+ if (tsi_end_p (iter))
+ {
+ /* Reached the start, we'll need to prepend further
+ statements. */
+ add = true;
+ iter = tsi_start (then_clause);
+ }
+ else
+ {
+ /* Found something, assert it is .DEFERRED_INIT for
+ DECL. */
+ tree t = tsi_stmt (iter);
+ gcc_checking_assert (TREE_CODE (t) == EXPR_STMT);
+ t = EXPR_STMT_EXPR (t);
+ gcc_checking_assert (TREE_CODE (t) == MODIFY_EXPR
+ && TREE_OPERAND (t, 0) == decl
+ && (TREE_CODE (TREE_OPERAND (t, 1))
+ == CALL_EXPR));
+ t = TREE_OPERAND (t, 1);
+ gcc_checking_assert (CALL_EXPR_FN (t) == NULL_TREE
+ && (CALL_EXPR_IFN (t)
+ == IFN_DEFERRED_INIT));
+ tsi_prev (&iter);
+ }
+ }
+ if (add)
+ {
+ /* If reached the start in this or some earlier iteration,
+ prepend .DEFERRED_INIT call for DECL. */
+ tree t = build_deferred_init_call (decl);
+ STMT_IS_FULL_EXPR_P (t) = 1;
+ tsi_link_before (&iter, t, TSI_CONTINUE_LINKING);
+ }
+ }
+ if (!add)
+ {
+ /* If .DEFERRED_INIT calls for all the decls were already there,
+ skip over case labels and if we find a LABEL_EXPR, return
+ its label. */
+ while (!tsi_end_p (iter)
+ && !case_label
+ && TREE_CODE (tsi_stmt (iter)) == CASE_LABEL_EXPR)
+ tsi_prev (&iter);
+ if (tsi_end_p (iter))
+ {
+ /* Only case labels were found and we are looking for normal
+ label, we'll need to add it. */
+ add = true;
+ iter = tsi_start (then_clause);
+ }
+ else if (!case_label
+ && TREE_CODE (tsi_stmt (iter)) == LABEL_EXPR)
+ /* Return existing label. */
+ lab = LABEL_EXPR_LABEL (tsi_stmt (iter));
+ else
+ {
+ /* We'll need to add a LABEL_EXPR or move CASE_LABEL_EXPR. */
+ gcc_checking_assert (case_label
+ || (TREE_CODE (tsi_stmt (iter))
+ == EXPR_STMT));
+ add = true;
+ tsi_next (&iter);
+ gcc_checking_assert (!tsi_end_p (iter));
+ }
+ }
+ if (add)
+ {
+ tree t;
+ if (case_label)
+ t = case_label;
+ else
+ {
+ lab = create_artificial_label (UNKNOWN_LOCATION);
+ t = build_stmt (UNKNOWN_LOCATION, LABEL_EXPR, lab);
+ }
+ tsi_link_before (&iter, t, TSI_CONTINUE_LINKING);
+ }
+ }
+ else
+ {
+ /* No IF_STMT created by this function found. Create it all
+ from scratch, so a LABEL_EXPR (or moved CASE_LABEL_EXPR)
+ followed by .DEFERRED_INIT calls inside of a new if (0). */
+ tree new_then = push_stmt_list ();
+ if (!case_label)
+ {
+ lab = create_artificial_label (UNKNOWN_LOCATION);
+ add_stmt (build_stmt (UNKNOWN_LOCATION, LABEL_EXPR, lab));
+ }
+ else
+ add_stmt (case_label);
+ for (unsigned int i = ndecls; i; --i)
+ add_stmt (build_deferred_init_call (decls[i - 1]));
+ new_then = pop_stmt_list (new_then);
+ tree stmt = build4 (IF_STMT, void_type_node, boolean_false_node,
+ new_then, void_node, NULL_TREE);
+ IF_STMT_VACUOUS_INIT_P (stmt) = 1;
+ if (tsi_end_p (iter))
+ {
+ iter = tsi_start (iter.container);
+ tsi_link_before (&iter, stmt, TSI_SAME_STMT);
+ }
+ else
+ tsi_link_after (&iter, stmt, TSI_CONTINUE_LINKING);
+ }
+ return lab;
+}
+
+/* Adjust backward gotos to named label ENT if they jump over vacuous
+ initializers if !!flag_auto_var_init. ITER is the location of
+ LABEL_EXPR for that named label. */
+
+static void
+adjust_backward_goto (named_label_entry *ent, tree_stmt_iterator iter)
+{
+ auto_vec<tree, 4> decls;
+ unsigned int i, max_cnt = ent->direct_goto->last ().n_bad_decls;
+ tree decl;
+ FOR_EACH_VEC_SAFE_ELT (ent->bad_decls, i, decl)
+ if (!decl_jump_unsafe (decl))
+ {
+ gcc_checking_assert (decl_instrument_init_bypass_p (decl));
+ decls.safe_push (decl);
+ if (decls.length () == max_cnt)
+ break;
+ }
+ named_label_bck_direct_goto *dgoto;
+ unsigned last = 0;
+ tree lab = NULL_TREE;
+ FOR_EACH_VEC_SAFE_ELT_REVERSE (ent->direct_goto, i, dgoto)
+ {
+ if (dgoto->n_bad_decls != last)
+ {
+ last = dgoto->n_bad_decls;
+ lab = maybe_add_deferred_init_calls (iter, NULL_TREE,
+ decls.address (), last);
+ }
+ *dgoto->direct_goto = lab;
+ }
+}
+
/* A subroutine of check_previous_goto_1 and check_goto to identify a branch
to the user. */
@@ -3771,13 +4153,19 @@ identify_goto (tree decl, location_t loc, const location_t *locus,
is OK. DECL is the LABEL_DECL or 0; LEVEL is the binding_level for
the jump context; NAMES are the names in scope in LEVEL at the jump
context; LOCUS is the source position of the jump or 0. COMPUTED
- is a vec of decls if the jump is a computed goto. Returns
- true if all is well. */
+ is a vec of decls if the jump is a computed goto. DIRECT_GOTO is a
+ vec of pointers to LABEL_DECLs that might need adjusting if vacuous
+ initializations are crossed for !!flag_auto_var_init. CASE_LABEL is
+ CASE_LABEL_EXPR to be moved if needed for the check_switch_goto case.
+ Returns non-zero if all is well, 2 if any vacuous initializers were
+ crossed. */
-static bool
-check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
+static int
+check_previous_goto_1 (tree decl, cp_binding_level *level, tree names,
bool exited_omp, const location_t *locus,
- vec<tree,va_gc> *computed)
+ vec<tree, va_gc> *computed,
+ vec<named_label_fwd_direct_goto, va_gc> *direct_goto,
+ tree case_label)
{
auto_diagnostic_group d;
cp_binding_level *b;
@@ -3785,6 +4173,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
int identified = 0;
bool saw_eh = false, saw_omp = false, saw_tm = false, saw_cxif = false;
bool saw_ceif = false, saw_se = false;
+ auto_vec<tree> vacuous_decls;
+ bool vacuous_inits = false;
if (exited_omp)
{
@@ -3807,7 +4197,15 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
{
bool problem = decl_jump_unsafe (new_decls);
if (! problem)
- continue;
+ {
+ if (decl_instrument_init_bypass_p (new_decls))
+ {
+ if (direct_goto || case_label)
+ vacuous_decls.safe_push (new_decls);
+ vacuous_inits = true;
+ }
+ continue;
+ }
if (!identified)
{
@@ -3906,7 +4304,30 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
}
}
- return !identified;
+ if (!vacuous_decls.is_empty () && !seen_error ())
+ {
+ tree_stmt_iterator iter = tsi_last (cur_stmt_list);
+ if (case_label)
+ {
+ gcc_checking_assert (tsi_stmt (iter) == case_label);
+ tsi_delink (&iter);
+ iter = tsi_last (cur_stmt_list);
+ }
+ tree lab = maybe_add_deferred_init_calls (iter, case_label,
+ vacuous_decls.address (),
+ vacuous_decls.length ());
+ if (lab)
+ {
+ unsigned int i;
+ named_label_fwd_direct_goto *dgoto;
+ FOR_EACH_VEC_SAFE_ELT (direct_goto, i, dgoto)
+ *dgoto->direct_goto = lab;
+ }
+ }
+
+ if (identified)
+ return 0;
+ return vacuous_inits ? 2 : 1;
}
static void
@@ -3914,24 +4335,27 @@ check_previous_goto (tree decl, struct named_label_use_entry *use)
{
check_previous_goto_1 (decl, use->binding_level,
use->names_in_scope, use->in_omp_scope,
- &use->o_goto_locus, use->computed_goto);
+ &use->o_goto_locus, use->computed_goto,
+ use->direct_goto, NULL_TREE);
+ vec_free (use->direct_goto);
}
-static bool
-check_switch_goto (cp_binding_level* level)
+static int
+check_switch_goto (cp_binding_level *level, tree case_label)
{
return check_previous_goto_1 (NULL_TREE, level, level->names,
- false, NULL, nullptr);
+ false, NULL, nullptr, nullptr, case_label);
}
-/* Check that a new jump to a label ENT is OK. COMPUTED is true
- if this is a possible target of a computed goto. */
+/* Check that a new jump to a label ENT is OK. DECLP is a pointer
+ to a LABEL_DECL for direct gotos and NULL for computed gotos. */
void
-check_goto_1 (named_label_entry *ent, bool computed)
+check_goto_1 (named_label_entry *ent, tree *declp)
{
auto_diagnostic_group d;
tree decl = ent->label_decl;
+ bool computed = declp == NULL;
/* If the label hasn't been defined yet, defer checking. */
if (! DECL_INITIAL (decl))
@@ -3939,8 +4363,14 @@ check_goto_1 (named_label_entry *ent, bool computed)
/* Don't bother creating another use if the last goto had the
same data, and will therefore create the same set of errors. */
if (ent->uses
+ && ent->uses->binding_level == current_binding_level
&& ent->uses->names_in_scope == current_binding_level->names)
- return;
+ {
+ if (declp && flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
+ vec_safe_push (ent->uses->direct_goto,
+ named_label_fwd_direct_goto { declp });
+ return;
+ }
named_label_use_entry *new_use
= ggc_alloc<named_label_use_entry> ();
@@ -3949,6 +4379,10 @@ check_goto_1 (named_label_entry *ent, bool computed)
new_use->o_goto_locus = input_location;
new_use->in_omp_scope = false;
new_use->computed_goto = computed ? make_tree_vector () : nullptr;
+ new_use->direct_goto = nullptr;
+ if (declp && flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
+ vec_safe_push (new_use->direct_goto,
+ named_label_fwd_direct_goto { declp });
new_use->next = ent->uses;
ent->uses = new_use;
@@ -3959,11 +4393,12 @@ check_goto_1 (named_label_entry *ent, bool computed)
int identified = 0;
tree bad;
unsigned ix;
+ unsigned n_bad_decls = 0;
if (ent->in_try_scope || ent->in_catch_scope || ent->in_transaction_scope
|| ent->in_constexpr_if || ent->in_consteval_if
|| ent->in_omp_scope || ent->in_stmt_expr
- || !vec_safe_is_empty (ent->bad_decls))
+ || ent->has_bad_decls)
{
enum diagnostics::kind diag_kind = diagnostics::kind::permerror;
if (ent->in_try_scope || ent->in_catch_scope || ent->in_constexpr_if
@@ -3978,8 +4413,14 @@ check_goto_1 (named_label_entry *ent, bool computed)
FOR_EACH_VEC_SAFE_ELT (ent->bad_decls, ix, bad)
{
bool problem = decl_jump_unsafe (bad);
+ if (!problem)
+ {
+ gcc_checking_assert (decl_instrument_init_bypass_p (bad));
+ n_bad_decls++;
+ continue;
+ }
- if (problem && DECL_ARTIFICIAL (bad))
+ if (DECL_ARTIFICIAL (bad))
{
/* Can't skip init of __exception_info. */
if (identified == 1)
@@ -4086,16 +4527,21 @@ check_goto_1 (named_label_entry *ent, bool computed)
break;
}
}
+
+ if (n_bad_decls && declp)
+ vec_safe_push (ent->direct_goto,
+ named_label_bck_direct_goto { declp, n_bad_decls });
}
-/* Check that a new jump to a label DECL is OK. Called by
+/* Check that a new jump to a label *DECLP is OK. Called by
finish_goto_stmt. */
void
-check_goto (tree decl)
+check_goto (tree *declp)
{
if (!named_labels)
return;
+ tree decl = *declp;
if (TREE_CODE (decl) != LABEL_DECL)
{
/* We don't know where a computed goto is jumping,
@@ -4106,7 +4552,7 @@ check_goto (tree decl)
{
auto ent = *iter;
if (ent->addressed)
- check_goto_1 (ent, true);
+ check_goto_1 (ent, NULL);
}
}
else
@@ -4115,7 +4561,7 @@ check_goto (tree decl)
named_label_entry **slot
= named_labels->find_slot_with_hash (DECL_NAME (decl), hash, NO_INSERT);
named_label_entry *ent = *slot;
- check_goto_1 (ent, false);
+ check_goto_1 (ent, declp);
}
}
@@ -4370,7 +4816,8 @@ finish_case_label (location_t loc, tree low_value, tree high_value)
if (cond && TREE_CODE (cond) == TREE_LIST)
cond = TREE_VALUE (cond);
- if (!check_switch_goto (switch_stack->level))
+ int chk_switch_goto = check_switch_goto (switch_stack->level, NULL_TREE);
+ if (!chk_switch_goto)
return error_mark_node;
type = SWITCH_STMT_TYPE (switch_stack->switch_stmt);
@@ -4382,6 +4829,9 @@ finish_case_label (location_t loc, tree low_value, tree high_value)
r = c_add_case_label (loc, switch_stack->cases, cond, low_value, high_value);
+ if (r != error_mark_node && chk_switch_goto == 2)
+ check_switch_goto (switch_stack->level, r);
+
/* After labels, make any new cleanups in the function go into their
own new (temporary) binding contour. */
for (p = current_binding_level;
@@ -19327,16 +19777,19 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
start_function_contracts (decl1);
if (!processing_template_decl
- && (flag_lifetime_dse > 1)
+ && flag_lifetime_dse > 1
&& DECL_CONSTRUCTOR_P (decl1)
- && !DECL_CLONED_FUNCTION_P (decl1)
/* Clobbering an empty base is harmful if it overlays real data. */
&& !is_empty_class (current_class_type)
/* We can't clobber safely for an implicitly-defined default constructor
because part of the initialization might happen before we enter the
constructor, via AGGR_INIT_ZERO_FIRST (c++/68006). */
- && !implicit_default_ctor_p (decl1))
- finish_expr_stmt (build_clobber_this (CLOBBER_OBJECT_BEGIN));
+ && !implicit_default_ctor_p (decl1)
+ && !lookup_attribute ("clobber *this",
+ DECL_ATTRIBUTES (current_class_ptr)))
+ DECL_ATTRIBUTES (current_class_ptr)
+ = tree_cons (get_identifier ("clobber *this"), NULL_TREE,
+ DECL_ATTRIBUTES (current_class_ptr));
if (!processing_template_decl
&& DECL_CONSTRUCTOR_P (decl1)
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index be873c1..5f814f3 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2341,6 +2341,7 @@ public:
EK_PARTIAL, /* A partial specialization. */
EK_USING, /* A using declaration (at namespace scope). */
EK_NAMESPACE, /* A namespace. */
+ EK_TU_LOCAL, /* A TU-local decl for ADL. */
EK_REDIRECT, /* Redirect to a template_decl. */
EK_EXPLICIT_HWM,
EK_BINDING = EK_EXPLICIT_HWM, /* Implicitly encoded. */
@@ -2351,6 +2352,8 @@ public:
EK_BITS = 3 /* Only need to encode below EK_EXPLICIT_HWM. */
};
+ static_assert (EK_EXPLICIT_HWM < (1u << EK_BITS),
+ "not enough bits reserved for entity_kind");
private:
/* Placement of bit fields in discriminator. */
@@ -2375,7 +2378,10 @@ private:
awkward. */
DB_TYPE_SPEC_BIT, /* Specialization in the type table. */
DB_FRIEND_SPEC_BIT, /* An instantiated template friend. */
+ DB_HWM,
};
+ static_assert (DB_HWM <= sizeof(discriminator) * CHAR_BIT,
+ "not enough bits in discriminator");
public:
/* The first slot is special for EK_SPECIALIZATIONS it is a
@@ -2700,7 +2706,9 @@ depset::entity_kind_name () const
/* Same order as entity_kind. */
static const char *const names[] =
{"decl", "specialization", "partial", "using",
- "namespace", "redirect", "binding"};
+ "namespace", "tu-local", "redirect", "binding"};
+ static_assert (ARRAY_SIZE (names) == EK_EXPLICIT_HWM + 1,
+ "names must have an entry for every explicit entity_kind");
entity_kind kind = get_entity_kind ();
gcc_checking_assert (kind < ARRAY_SIZE (names));
return names[kind];
@@ -9986,6 +9994,16 @@ trees_out::find_tu_local_decl (tree t)
return cp_walk_tree_without_duplicates (&t, walker, this);
}
+/* Get the name for TU-local decl T to be used in diagnostics. */
+
+static tree
+name_for_tu_local_decl (tree t)
+{
+ int flags = (TFF_SCOPE | TFF_DECL_SPECIFIERS);
+ const char *str = decl_as_string (t, flags);
+ return get_identifier (str);
+}
+
/* Stream out tree node T. We automatically create local back
references, which is essentially a single pass lisp
self-referential structure pretty-printer. */
@@ -10030,8 +10048,7 @@ trees_out::tree_node (tree t)
&& dump ("Writing TU-local entity:%d %C:%N",
tag, TREE_CODE (t), t);
}
- /* TODO: Get a more descriptive name? */
- tree_node (DECL_NAME (local_decl));
+ tree_node (name_for_tu_local_decl (local_decl));
if (state)
state->write_location (*this, DECL_SOURCE_LOCATION (local_decl));
goto done;
@@ -14194,6 +14211,8 @@ depset::hash::make_dependency (tree decl, entity_kind ek)
gcc_checking_assert (!is_key_order ());
if (ek == EK_USING)
gcc_checking_assert (TREE_CODE (decl) == OVERLOAD);
+ if (ek == EK_TU_LOCAL)
+ gcc_checking_assert (DECL_DECLARES_FUNCTION_P (decl));
if (TREE_CODE (decl) == TEMPLATE_DECL)
/* The template should have copied these from its result decl. */
@@ -14394,7 +14413,8 @@ depset::hash::make_dependency (tree decl, entity_kind ek)
dump (dumper::DEPEND)
&& dump ("%s on %s %C:%N found",
ek == EK_REDIRECT ? "Redirect"
- : for_binding ? "Binding" : "Dependency",
+ : (for_binding || ek == EK_TU_LOCAL) ? "Binding"
+ : "Dependency",
dep->entity_kind_name (), TREE_CODE (decl), decl);
return dep;
@@ -14565,9 +14585,21 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
than trying to clear out bindings after the fact. */
return false;
+ bool internal_decl = false;
if (!header_module_p () && data->hash->is_tu_local_entity (decl))
- /* Ignore TU-local entitites. */
- return false;
+ {
+ /* A TU-local entity. For ADL we still need to create bindings
+ for internal-linkage functions attached to a named module. */
+ if (DECL_DECLARES_FUNCTION_P (inner)
+ && DECL_LANG_SPECIFIC (inner)
+ && DECL_MODULE_ATTACH_P (inner))
+ {
+ gcc_checking_assert (!DECL_MODULE_EXPORT_P (inner));
+ internal_decl = true;
+ }
+ else
+ return false;
+ }
if ((TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == TYPE_DECL)
@@ -14662,8 +14694,13 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
OVL_EXPORT_P (decl) = true;
}
- depset *dep = data->hash->make_dependency
- (decl, flags & WMB_Using ? EK_USING : EK_FOR_BINDING);
+ entity_kind ek = EK_FOR_BINDING;
+ if (internal_decl)
+ ek = EK_TU_LOCAL;
+ else if (flags & WMB_Using)
+ ek = EK_USING;
+
+ depset *dep = data->hash->make_dependency (decl, ek);
if (flags & WMB_Hidden)
dep->set_hidden_binding ();
data->binding->deps.safe_push (dep);
@@ -15114,9 +15151,12 @@ depset::hash::find_dependencies (module_state *module)
walker.begin ();
if (current->get_entity_kind () == EK_USING)
walker.tree_node (OVL_FUNCTION (decl));
+ else if (current->get_entity_kind () == EK_TU_LOCAL)
+ /* We only stream its name and location. */
+ module->note_location (DECL_SOURCE_LOCATION (decl));
else if (TREE_VISITED (decl))
/* A global tree. */;
- else if (item->get_entity_kind () == EK_NAMESPACE)
+ else if (current->get_entity_kind () == EK_NAMESPACE)
{
module->note_location (DECL_SOURCE_LOCATION (decl));
add_namespace_context (current, CP_DECL_CONTEXT (decl));
@@ -15231,6 +15271,12 @@ binding_cmp (const void *a_, const void *b_)
return a_implicit ? -1 : +1; /* Implicit first. */
}
+ /* TU-local before non-TU-local. */
+ bool a_internal = a->get_entity_kind () == depset::EK_TU_LOCAL;
+ bool b_internal = b->get_entity_kind () == depset::EK_TU_LOCAL;
+ if (a_internal != b_internal)
+ return a_internal ? -1 : +1; /* Internal first. */
+
/* Hidden before non-hidden. */
bool a_hidden = a->is_hidden ();
bool b_hidden = b->is_hidden ();
@@ -15565,12 +15611,15 @@ sort_cluster (depset::hash *original, depset *scc[], unsigned size)
use_lwm--;
break;
}
- /* We must have copied a using, so move it too. */
+ /* We must have copied a using or TU-local, so move it too. */
dep = scc[ix];
- gcc_checking_assert (dep->get_entity_kind () == depset::EK_USING);
+ gcc_checking_assert
+ (dep->get_entity_kind () == depset::EK_USING
+ || dep->get_entity_kind () == depset::EK_TU_LOCAL);
/* FALLTHROUGH */
case depset::EK_USING:
+ case depset::EK_TU_LOCAL:
if (--use_lwm != ix)
{
scc[ix] = scc[use_lwm];
@@ -16570,6 +16619,7 @@ enum ct_bind_flags
cbf_export = 0x1, /* An exported decl. */
cbf_hidden = 0x2, /* A hidden (friend) decl. */
cbf_using = 0x4, /* A using decl. */
+ cbf_internal = 0x8, /* A TU-local decl. */
};
/* DEP belongs to a different cluster, seed it to prevent
@@ -16641,7 +16691,9 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size,
gcc_checking_assert (dep->is_import ()
|| TREE_VISITED (dep->get_entity ())
|| (dep->get_entity_kind ()
- == depset::EK_USING));
+ == depset::EK_USING)
+ || (dep->get_entity_kind ()
+ == depset::EK_TU_LOCAL));
}
}
break;
@@ -16654,6 +16706,7 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size,
/* FALLTHROUGH */
case depset::EK_USING:
+ case depset::EK_TU_LOCAL:
gcc_checking_assert (!b->is_import ()
&& !b->is_unreached ());
dump (dumper::CLUSTER)
@@ -16726,7 +16779,9 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size,
depset *dep = b->deps[jx];
tree bound = dep->get_entity ();
unsigned flags = 0;
- if (dep->get_entity_kind () == depset::EK_USING)
+ if (dep->get_entity_kind () == depset::EK_TU_LOCAL)
+ flags |= cbf_internal;
+ else if (dep->get_entity_kind () == depset::EK_USING)
{
tree ovl = bound;
bound = OVL_FUNCTION (bound);
@@ -16752,7 +16807,13 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size,
gcc_checking_assert (DECL_P (bound));
sec.i (flags);
- sec.tree_node (bound);
+ if (flags & cbf_internal)
+ {
+ sec.tree_node (name_for_tu_local_decl (bound));
+ write_location (sec, DECL_SOURCE_LOCATION (bound));
+ }
+ else
+ sec.tree_node (bound);
}
/* Terminate the list. */
@@ -16761,6 +16822,7 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size,
break;
case depset::EK_USING:
+ case depset::EK_TU_LOCAL:
dump () && dump ("Depset:%u %s %C:%N", ix, b->entity_kind_name (),
TREE_CODE (decl), decl);
break;
@@ -16878,6 +16940,7 @@ module_state::read_cluster (unsigned snum)
tree name = sec.tree_node ();
tree decls = NULL_TREE;
tree visible = NULL_TREE;
+ tree internal = NULL_TREE;
tree type = NULL_TREE;
bool dedup = false;
bool global_p = is_header ();
@@ -16893,6 +16956,23 @@ module_state::read_cluster (unsigned snum)
if ((flags & cbf_hidden)
&& (flags & (cbf_using | cbf_export)))
sec.set_overrun ();
+ if ((flags & cbf_internal)
+ && flags != cbf_internal)
+ sec.set_overrun ();
+
+ if (flags & cbf_internal)
+ {
+ tree name = sec.tree_node ();
+ location_t loc = read_location (sec);
+ if (sec.get_overrun ())
+ break;
+
+ tree decl = make_node (TU_LOCAL_ENTITY);
+ TU_LOCAL_ENTITY_NAME (decl) = name;
+ TU_LOCAL_ENTITY_LOCATION (decl) = loc;
+ internal = tree_cons (NULL_TREE, decl, internal);
+ continue;
+ }
tree decl = sec.tree_node ();
if (sec.get_overrun ())
@@ -16987,7 +17067,7 @@ module_state::read_cluster (unsigned snum)
}
}
- if (!decls)
+ if (!decls && !internal)
sec.set_overrun ();
if (sec.get_overrun ())
@@ -16996,7 +17076,7 @@ module_state::read_cluster (unsigned snum)
dump () && dump ("Binding of %P", ns, name);
if (!set_module_binding (ns, name, mod, global_p,
is_module () || is_partition (),
- decls, type, visible))
+ decls, type, visible, internal))
sec.set_overrun ();
}
break;
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 32af7a6..8d7fc06 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -353,6 +353,8 @@ append_imported_binding_slot (tree *slot, tree name, unsigned ix)
tree new_vec = make_binding_vec (name, want);
BINDING_VECTOR_NUM_CLUSTERS (new_vec) = have + 1;
+ BINDING_VECTOR_INTERNAL_DECLS (new_vec)
+ = BINDING_VECTOR_INTERNAL_DECLS (*slot);
BINDING_VECTOR_GLOBAL_DUPS_P (new_vec)
= BINDING_VECTOR_GLOBAL_DUPS_P (*slot);
BINDING_VECTOR_PARTITION_DUPS_P (new_vec)
@@ -1304,10 +1306,34 @@ name_lookup::adl_namespace_fns (tree scope, bitmap imports,
}
/* For lookups on the instantiation path we can see any
- module-linkage declaration; otherwise we should only
- see exported decls. */
+ declarations visible at any point on the path;
+ otherwise we should only see exported decls. */
if (on_inst_path)
- bind = STAT_DECL (bind);
+ {
+ /* If there are any internal functions visible, naming
+ them outside that module is ill-formed. */
+ auto_diagnostic_group d;
+ if (MODULE_BINDING_INTERNAL_DECLS_P (bind)
+ && pedwarn (input_location, OPT_Wexternal_tu_local,
+ "overload set for argument-dependent "
+ "lookup of %<%D::%D%> in module %qs "
+ "contains TU-local entities",
+ scope, name, module_name (mod, false)))
+ {
+ tree *tu_locals
+ = BINDING_VECTOR_INTERNAL_DECLS (val)->get (mod);
+ gcc_checking_assert (tu_locals && *tu_locals);
+ for (tree t = *tu_locals; t; t = TREE_CHAIN (t))
+ {
+ tree decl = TREE_VALUE (t);
+ inform (TU_LOCAL_ENTITY_LOCATION (decl),
+ "ignoring %qD declared here "
+ "with internal linkage",
+ TU_LOCAL_ENTITY_NAME (decl));
+ }
+ }
+ bind = STAT_DECL (bind);
+ }
else
bind = STAT_VISIBLE (bind);
}
@@ -4427,18 +4453,21 @@ import_module_binding (tree ns, tree name, unsigned mod, unsigned snum)
/* An import of MODULE is binding NS::NAME. There should be no
existing binding for >= MODULE. GLOBAL_P indicates whether the
bindings include global module entities. PARTITION_P is true if
- it is part of the current module. VALUE and TYPE are the value
- and type bindings. VISIBLE are the value bindings being exported. */
+ it is part of the current module. VALUE and TYPE are the value
+ and type bindings. VISIBLE are the value bindings being exported.
+ INTERNAL is a TREE_LIST of any TU-local names visible for ADL. */
bool
set_module_binding (tree ns, tree name, unsigned mod, bool global_p,
- bool partition_p, tree value, tree type, tree visible)
+ bool partition_p, tree value, tree type, tree visible,
+ tree internal)
{
- if (!value)
+ if (!value && !internal)
/* Bogus BMIs could give rise to nothing to bind. */
return false;
- gcc_assert (TREE_CODE (value) != NAMESPACE_DECL
+ gcc_assert (!value
+ || TREE_CODE (value) != NAMESPACE_DECL
|| DECL_NAMESPACE_ALIAS (value));
gcc_checking_assert (mod);
@@ -4450,7 +4479,7 @@ set_module_binding (tree ns, tree name, unsigned mod, bool global_p,
return false;
tree bind = value;
- if (type || visible != bind || partition_p || global_p)
+ if (type || visible != bind || internal || partition_p || global_p)
{
bind = stat_hack (bind, type);
STAT_VISIBLE (bind) = visible;
@@ -4459,6 +4488,17 @@ set_module_binding (tree ns, tree name, unsigned mod, bool global_p,
STAT_TYPE_VISIBLE_P (bind) = true;
}
+ /* If this has internal declarations, track them for diagnostics. */
+ if (internal)
+ {
+ if (!BINDING_VECTOR_INTERNAL_DECLS (*slot))
+ BINDING_VECTOR_INTERNAL_DECLS (*slot)
+ = module_tree_map_t::create_ggc ();
+ bool existed = BINDING_VECTOR_INTERNAL_DECLS (*slot)->put (mod, internal);
+ gcc_checking_assert (!existed);
+ MODULE_BINDING_INTERNAL_DECLS_P (bind) = true;
+ }
+
/* Note if this is this-module and/or global binding. */
if (partition_p)
MODULE_BINDING_PARTITION_P (bind) = true;
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 5b142e7..3815b8c 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -142,15 +142,23 @@ struct GTY(()) binding_cluster
#define BINDING_VECTOR_CLUSTER(NODE,IX) \
(((tree_binding_vec *)BINDING_VECTOR_CHECK (NODE))->vec[IX])
+struct module_tree_map_traits
+ : simple_hashmap_traits<int_hash<unsigned, 0>, tree> {};
+typedef hash_map<unsigned, tree, module_tree_map_traits> module_tree_map_t;
+
struct GTY(()) tree_binding_vec {
struct tree_base base;
tree name;
+ module_tree_map_t *internal_decls;
binding_cluster GTY((length ("%h.base.u.dependence_info.base"))) vec[1];
};
/* The name of a module vector. */
#define BINDING_VECTOR_NAME(NODE) \
(((tree_binding_vec *)BINDING_VECTOR_CHECK (NODE))->name)
+/* A collection of internal functions for ADL in this binding. */
+#define BINDING_VECTOR_INTERNAL_DECLS(NODE) \
+ (((tree_binding_vec *)BINDING_VECTOR_CHECK (NODE))->internal_decls)
/* tree_binding_vec does uses base.u.dependence_info.base field for
length. It does not have lang_flag etc available! */
@@ -166,6 +174,11 @@ struct GTY(()) tree_binding_vec {
#define BINDING_VECTOR_PARTITION_DUPS_P(NODE) \
(BINDING_VECTOR_CHECK (NODE)->base.volatile_flag)
+/* True if the binding slot has internal-linkage functions that should
+ cause ADL to error. */
+#define MODULE_BINDING_INTERNAL_DECLS_P(NODE) \
+ (OVERLOAD_CHECK (NODE)->base.private_flag)
+
/* These two flags indicate the provenence of the bindings on this
particular vector slot. We can of course determine this from slot
number, but that's a relatively expensive lookup. This avoids
@@ -491,7 +504,8 @@ extern bool import_module_binding (tree ctx, tree name, unsigned mod,
unsigned snum);
extern bool set_module_binding (tree ctx, tree name, unsigned mod,
bool global_p, bool partition_p,
- tree value, tree type, tree visible);
+ tree value, tree type, tree visible,
+ tree internal);
extern void add_module_namespace_decl (tree ns, tree decl);
enum WMB_Flags
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 8d1187f..362cddb 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -28124,6 +28124,7 @@ cp_parser_class_specifier (cp_parser* parser)
bool in_switch_statement_p;
bool saved_in_unbraced_linkage_specification_p;
bool saved_in_unbraced_export_declaration_p;
+ bool saved_auto_is_implicit_function_template_parm_p;
tree old_scope = NULL_TREE;
tree scope = NULL_TREE;
cp_token *closing_brace;
@@ -28181,6 +28182,10 @@ cp_parser_class_specifier (cp_parser* parser)
saved_in_unbraced_export_declaration_p
= parser->in_unbraced_export_declaration_p;
parser->in_unbraced_export_declaration_p = false;
+ saved_auto_is_implicit_function_template_parm_p
+ = parser->auto_is_implicit_function_template_parm_p;
+ parser->auto_is_implicit_function_template_parm_p = false;
+
/* 'this' from an enclosing non-static member function is unavailable. */
tree saved_ccp = current_class_ptr;
tree saved_ccr = current_class_ref;
@@ -28571,6 +28576,8 @@ cp_parser_class_specifier (cp_parser* parser)
= saved_in_unbraced_linkage_specification_p;
parser->in_unbraced_export_declaration_p
= saved_in_unbraced_export_declaration_p;
+ parser->auto_is_implicit_function_template_parm_p
+ = saved_auto_is_implicit_function_template_parm_p;
current_class_ptr = saved_ccp;
current_class_ref = saved_ccr;
@@ -31179,10 +31186,10 @@ cp_parser_asm_label_list (cp_parser* parser)
if (TREE_CODE (label) == LABEL_DECL)
{
TREE_USED (label) = 1;
- check_goto (label);
name = build_string (IDENTIFIER_LENGTH (identifier),
IDENTIFIER_POINTER (identifier));
labels = tree_cons (name, label, labels);
+ check_goto (&TREE_VALUE (labels));
}
}
/* If the next token is not a `,', then the list is
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index bd60d51..9b32049 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -8928,8 +8928,11 @@ convert_template_argument (tree parm,
orig_arg = TREE_OPERAND (orig_arg, 0);
if (!uses_template_parms (t)
- && !(force_conv ? uses_template_parms (orig_arg)
- : type_dependent_expression_p (orig_arg)))
+ && !type_dependent_expression_p (orig_arg)
+ && !(force_conv
+ && !(same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (orig_arg), t))
+ && value_dependent_expression_p (orig_arg)))
/* We used to call digest_init here. However, digest_init
will report errors, which we don't want when complain
is zero. More importantly, digest_init will try too
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 1937ace..8d0210e 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -919,10 +919,12 @@ finish_goto_stmt (tree destination)
}
}
- check_goto (destination);
-
add_stmt (build_predict_expr (PRED_GOTO, NOT_TAKEN));
- return add_stmt (build_stmt (input_location, GOTO_EXPR, destination));
+
+ tree stmt = build_stmt (input_location, GOTO_EXPR, destination);
+ check_goto (&TREE_OPERAND (stmt, 0));
+
+ return add_stmt (stmt);
}
/* Returns true if T corresponds to an assignment operator expression. */
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 03b58ff..c6ce7e9 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5591,6 +5591,23 @@ handle_maybe_unused_attribute (tree *node, tree name, tree args, int flags,
return ret;
}
+/* The C++26 [[indeterminate]] attribute. */
+
+static tree
+handle_indeterminate_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != PARM_DECL
+ && (!VAR_P (*node) || is_global_var (*node)))
+ {
+ pedwarn (input_location, OPT_Wattributes,
+ "%qE on declaration other than parameter or automatic variable",
+ name);
+ *no_add_attrs = true;
+ }
+ return NULL_TREE;
+}
+
/* Table of valid C++ attributes. */
static const attribute_spec cxx_gnu_attributes[] =
{
@@ -5630,6 +5647,8 @@ static const attribute_spec std_attributes[] =
handle_noreturn_attribute, attr_noreturn_exclusions },
{ "carries_dependency", 0, 0, true, false, false, false,
handle_carries_dependency_attribute, NULL },
+ { "indeterminate", 0, 0, true, false, false, false,
+ handle_indeterminate_attribute, NULL },
{ "pre", 0, -1, false, false, false, false,
handle_contract_attribute, NULL },
{ "post", 0, -1, false, false, false, false,
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 492ca29..f93fe43 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -272,7 +272,7 @@ in the following sections.
-Woverloaded-virtual -Wno-pmf-conversions -Wself-move -Wsign-promo
-Wsized-deallocation -Wsuggest-final-methods
-Wsuggest-final-types -Wsuggest-override -Wno-template-body
--Wno-template-id-cdtor -Wtemplate-names-tu-local
+-Wno-template-id-cdtor -Wtemplate-names-tu-local -Wno-external-tu-local
-Wno-terminate -Wno-vexing-parse -Wvirtual-inheritance
-Wno-virtual-move-assign -Wvolatile}
@@ -4759,6 +4759,32 @@ The presence of an explicit instantiation silences the warning.
This flag is enabled by @option{-Wextra}.
+@opindex Wexternal-tu-local
+@opindex Wno-external-tu-local
+@item -Wno-external-tu-local
+Warn when naming a TU-local entity outside of the translation unit it
+was declared in. Such declarations will be ignored during name lookup.
+This can occur when performing ADL from a template declared in the same
+TU as the internal function:
+
+@smallexample
+export module M;
+template <typename T> void foo(T t) @{
+ bar(t);
+@}
+struct S @{@} s;
+static void bar(S) @{@} // internal linkage
+
+// instantiating foo(s) from outside this TU can see ::bar,
+// but naming it there is ill-formed.
+@end smallexample
+
+This can be worked around by making @code{bar} attached to the global
+module, using @code{extern "C++"}.
+
+This warning is enabled by default, and is upgraded to an error by
+@option{-pedantic-errors}.
+
@opindex Wterminate
@opindex Wno-terminate
@item -Wno-terminate @r{(C++ and Objective-C++ only)}
@@ -14725,27 +14751,25 @@ and @option{-fauto-profile}.
@opindex ftrivial-auto-var-init
@item -ftrivial-auto-var-init=@var{choice}
-Initialize automatic variables with either a pattern or with zeroes to increase
-the security and predictability of a program by preventing uninitialized memory
-disclosure and use.
+Initialize automatic variables or temporary objects with either a pattern or with
+zeroes to increase the security and predictability of a program by preventing
+uninitialized memory disclosure and use.
GCC still considers an automatic variable that doesn't have an explicit
initializer as uninitialized, @option{-Wuninitialized} and
@option{-Wanalyzer-use-of-uninitialized-value} will still report
-warning messages on such automatic variables and the compiler will
-perform optimization as if the variable were uninitialized.
+warning messages on such automatic variables or temporary objects and the
+compiler will perform optimization as if the variable were uninitialized.
With this option, GCC will also initialize any padding of automatic variables
-that have structure or union types to zeroes.
-However, the current implementation cannot initialize automatic variables that
-are declared between the controlling expression and the first case of a
-@code{switch} statement. Using @option{-Wtrivial-auto-var-init} to report all
-such cases.
+or temporary objects that have structure or union types to zeroes.
+However, the current implementation cannot initialize automatic variables
+whose initialization is bypassed through @code{switch} or @code{goto}
+statement. Using @option{-Wtrivial-auto-var-init} to report all such cases.
The three values of @var{choice} are:
@itemize @bullet
@item
@samp{uninitialized} doesn't initialize any automatic variables.
-This is C and C++'s default.
@item
@samp{pattern} Initialize automatic variables with values which will likely
@@ -14759,7 +14783,10 @@ The values used for pattern initialization might be changed in the future.
@samp{zero} Initialize automatic variables with zeroes.
@end itemize
-The default is @samp{uninitialized}.
+The default is @samp{uninitialized} except for C++26, in which case
+if @option{-ftrivial-auto-var-init=} is not specified at all automatic
+variables or temporary objects are zero initialized, but zero initialization
+of padding bits does not happen.
Note that the initializer values, whether @samp{zero} or @samp{pattern},
refer to data representation (in memory or machine registers), rather
@@ -14772,7 +14799,7 @@ with the bit patterns @code{0x00} or @code{0xFE}, depending on
@var{choice}, whether or not these representations stand for values in
that range, and even if they do, the interpretation of the value held by
the variable will depend on the bias. A @samp{hardbool} variable that
-uses say @code{0X5A} and @code{0xA5} for @code{false} and @code{true},
+uses say @code{0x5A} and @code{0xA5} for @code{false} and @code{true},
respectively, will trap with either @samp{choice} of trivial
initializer, i.e., @samp{zero} initialization will not convert to the
representation for @code{false}, even if it would for a @code{static}
@@ -14783,7 +14810,8 @@ are initialized with @code{false} (zero), even when @samp{pattern} is
requested.
You can control this behavior for a specific variable by using the variable
-attribute @code{uninitialized} (@pxref{Variable Attributes}).
+attribute @code{uninitialized} standard attribute (@pxref{Variable Attributes})
+or the C++26 @code{[[indeterminate]]}.
@opindex fvect-cost-model
@item -fvect-cost-model=@var{model}
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index bf681c3..44a90be 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -288,7 +288,8 @@ enum vect_cost_model {
enum auto_init_type {
AUTO_INIT_UNINITIALIZED = 0,
AUTO_INIT_PATTERN = 1,
- AUTO_INIT_ZERO = 2
+ AUTO_INIT_ZERO = 2,
+ AUTO_INIT_CXX26 = 3
};
/* Initialization of padding bits with zeros. */
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 9c5aa06..d8725e4 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -2103,13 +2103,13 @@ gimple_add_padding_init_for_auto_var (tree decl, bool is_vla,
/* Return true if the DECL need to be automaticly initialized by the
compiler. */
static bool
-is_var_need_auto_init (tree decl)
+var_needs_auto_init_p (tree decl)
{
if (auto_var_p (decl)
- && (TREE_CODE (decl) != VAR_DECL
- || !DECL_HARD_REGISTER (decl))
- && (flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
- && (!lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl)))
+ && (TREE_CODE (decl) != VAR_DECL || !DECL_HARD_REGISTER (decl))
+ && flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && !lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl))
+ && !lookup_attribute ("indeterminate", DECL_ATTRIBUTES (decl))
&& !OPAQUE_TYPE_P (TREE_TYPE (decl))
&& !is_empty_type (TREE_TYPE (decl)))
return true;
@@ -2222,7 +2222,7 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p)
/* When there is no explicit initializer, if the user requested,
We should insert an artifical initializer for this automatic
variable. */
- else if (is_var_need_auto_init (decl)
+ else if (var_needs_auto_init_p (decl)
&& !decl_had_value_expr_p)
{
gimple_add_init_for_auto_var (decl,
@@ -2316,27 +2316,6 @@ emit_warn_switch_unreachable (gimple *stmt)
/* Don't warn for compiler-generated gotos. These occur
in Duff's devices, for example. */
return NULL;
- else if ((flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
- && ((gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
- || (gimple_call_builtin_p (stmt, BUILT_IN_CLEAR_PADDING)
- && (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1)))
- || (is_gimple_assign (stmt)
- && gimple_assign_single_p (stmt)
- && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
- && gimple_call_internal_p (
- SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt)),
- IFN_DEFERRED_INIT))))
- /* Don't warn for compiler-generated initializations for
- -ftrivial-auto-var-init.
- There are 3 cases:
- case 1: a call to .DEFERRED_INIT;
- case 2: a call to __builtin_clear_padding with the 2nd argument is
- present and non-zero;
- case 3: a gimple assign store right after the call to .DEFERRED_INIT
- that has the LHS of .DEFERRED_INIT as the RHS as following:
- _1 = .DEFERRED_INIT (4, 2, &"i1"[0]);
- i1 = _1. */
- return NULL;
else
warning_at (gimple_location (stmt), OPT_Wswitch_unreachable,
"statement will never be executed");
@@ -2384,6 +2363,18 @@ warn_switch_unreachable_and_auto_init_r (gimple_stmt_iterator *gsi_p,
there will be non-debug stmts too, and we'll catch those. */
break;
+ case GIMPLE_ASSIGN:
+ /* See comment below in the GIMPLE_CALL case. */
+ if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && gimple_assign_single_p (stmt)
+ && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
+ {
+ gimple *g = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
+ if (gimple_call_internal_p (g, IFN_DEFERRED_INIT))
+ break;
+ }
+ goto do_default;
+
case GIMPLE_LABEL:
/* Stop till the first Label. */
return integer_zero_node;
@@ -2393,24 +2384,41 @@ warn_switch_unreachable_and_auto_init_r (gimple_stmt_iterator *gsi_p,
*handled_ops_p = false;
break;
}
- if (warn_trivial_auto_var_init
- && flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ /* Don't warn for compiler-generated initializations for
+ -ftrivial-auto-var-init for -Wswitch-unreachable. Though
+ do warn for -Wtrivial-auto-var-init.
+ There are 3 cases:
+ case 1: a call to .DEFERRED_INIT;
+ case 2: a call to __builtin_clear_padding with the 2nd argument is
+ present and non-zero;
+ case 3: a gimple assign store right after the call to .DEFERRED_INIT
+ that has the LHS of .DEFERRED_INIT as the RHS as following:
+ _1 = .DEFERRED_INIT (4, 2, &"i1"[0]);
+ i1 = _1.
+ case 3 is handled above in the GIMPLE_ASSIGN case. */
+ if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
&& gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
{
- /* Get the variable name from the 3rd argument of call. */
- tree var_name = gimple_call_arg (stmt, 2);
- var_name = TREE_OPERAND (TREE_OPERAND (var_name, 0), 0);
- const char *var_name_str = TREE_STRING_POINTER (var_name);
-
- warning_at (gimple_location (stmt), OPT_Wtrivial_auto_var_init,
- "%qs cannot be initialized with "
- "%<-ftrivial-auto-var_init%>",
- var_name_str);
+ if (warn_trivial_auto_var_init)
+ {
+ /* Get the variable name from the 3rd argument of call. */
+ tree var_name = gimple_call_arg (stmt, 2);
+ var_name = TREE_OPERAND (TREE_OPERAND (var_name, 0), 0);
+ const char *var_name_str = TREE_STRING_POINTER (var_name);
+
+ warning_at (gimple_location (stmt), OPT_Wtrivial_auto_var_init,
+ "%qs cannot be initialized with "
+ "%<-ftrivial-auto-var_init%>", var_name_str);
+ }
break;
}
-
+ if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && gimple_call_builtin_p (stmt, BUILT_IN_CLEAR_PADDING)
+ && (bool) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1)))
+ break;
/* Fall through. */
default:
+ do_default:
/* check the first "real" statement (not a decl/lexical scope/...), issue
warning if needed. */
if (warn_switch_unreachable && !unreachable_issued)
@@ -2490,26 +2498,39 @@ last_stmt_in_scope (gimple *stmt)
if (!stmt)
return NULL;
+ auto last_stmt_in_seq = [] (gimple_seq s)
+ {
+ gimple_seq_node n;
+ for (n = gimple_seq_last (s);
+ n && (is_gimple_debug (n)
+ || (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && gimple_call_internal_p (n, IFN_DEFERRED_INIT)));
+ n = n->prev)
+ if (n == s)
+ return (gimple *) NULL;
+ return (gimple *) n;
+ };
+
switch (gimple_code (stmt))
{
case GIMPLE_BIND:
{
gbind *bind = as_a <gbind *> (stmt);
- stmt = gimple_seq_last_nondebug_stmt (gimple_bind_body (bind));
+ stmt = last_stmt_in_seq (gimple_bind_body (bind));
return last_stmt_in_scope (stmt);
}
case GIMPLE_TRY:
{
gtry *try_stmt = as_a <gtry *> (stmt);
- stmt = gimple_seq_last_nondebug_stmt (gimple_try_eval (try_stmt));
+ stmt = last_stmt_in_seq (gimple_try_eval (try_stmt));
gimple *last_eval = last_stmt_in_scope (stmt);
if (gimple_stmt_may_fallthru (last_eval)
&& (last_eval == NULL
|| !gimple_call_internal_p (last_eval, IFN_FALLTHROUGH))
&& gimple_try_kind (try_stmt) == GIMPLE_TRY_FINALLY)
{
- stmt = gimple_seq_last_nondebug_stmt (gimple_try_cleanup (try_stmt));
+ stmt = last_stmt_in_seq (gimple_try_cleanup (try_stmt));
return last_stmt_in_scope (stmt);
}
else
@@ -2662,8 +2683,16 @@ collect_fallthrough_labels (gimple_stmt_iterator *gsi_p,
}
else if (gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_ASAN_MARK))
;
+ else if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && gimple_call_internal_p (gsi_stmt (*gsi_p),
+ IFN_DEFERRED_INIT))
+ ;
else if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_PREDICT)
;
+ else if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_GOTO
+ && VACUOUS_INIT_LABEL_P (gimple_goto_dest (gsi_stmt (*gsi_p))))
+ ;
else if (!is_gimple_debug (gsi_stmt (*gsi_p)))
prev = gsi_stmt (*gsi_p);
gsi_next (gsi_p);
@@ -2700,9 +2729,13 @@ should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label)
{
tree l;
while (!gsi_end_p (gsi)
- && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL
- && (l = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi))))
- && !case_label_p (&gimplify_ctxp->case_labels, l))
+ && ((gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL
+ && (l
+ = gimple_label_label (as_a <glabel *> (gsi_stmt (gsi))))
+ && !case_label_p (&gimplify_ctxp->case_labels, l))
+ || (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && gimple_call_internal_p (gsi_stmt (gsi),
+ IFN_DEFERRED_INIT))))
gsi_next_nondebug (&gsi);
if (gsi_end_p (gsi) || gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
return false;
@@ -2715,7 +2748,10 @@ should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label)
/* Skip all immediately following labels. */
while (!gsi_end_p (gsi)
&& (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL
- || gimple_code (gsi_stmt (gsi)) == GIMPLE_PREDICT))
+ || gimple_code (gsi_stmt (gsi)) == GIMPLE_PREDICT
+ || (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && gimple_call_internal_p (gsi_stmt (gsi),
+ IFN_DEFERRED_INIT))))
gsi_next_nondebug (&gsi);
/* { ... something; default:; } */
@@ -2892,7 +2928,33 @@ expand_FALLTHROUGH_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
gimple_stmt_iterator gsi2 = *gsi_p;
stmt = gsi_stmt (gsi2);
- if (gimple_code (stmt) == GIMPLE_GOTO && !gimple_has_location (stmt))
+ if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && gimple_code (stmt) == GIMPLE_GOTO
+ && VACUOUS_INIT_LABEL_P (gimple_goto_dest (stmt)))
+ {
+ /* Handle for C++ artificial -ftrivial-auto-var-init=
+ sequences. Those look like:
+ goto lab1;
+ lab2:;
+ v1 = .DEFERRED_INIT (...);
+ v2 = .DEFERRED_INIT (...);
+ lab3:;
+ v3 = .DEFERRED_INIT (...);
+ lab1:;
+ In this case, a case/default label can be either in between
+ the GIMPLE_GOTO and the corresponding GIMPLE_LABEL, if jumps
+ from the switch condition to the case/default label cross
+ vacuous initialization of some variables, or after the
+ corresponding GIMPLE_LABEL, if those jumps don't cross
+ any such initialization but there is an adjacent named label
+ which crosses such initialization. So, for the purpose of
+ this function, just ignore the goto but until reaching the
+ corresponding GIMPLE_LABEL allow also .DEFERRED_INIT
+ calls. */
+ gsi_next (&gsi2);
+ }
+ else if (gimple_code (stmt) == GIMPLE_GOTO
+ && !gimple_has_location (stmt))
{
/* Go on until the artificial label. */
tree goto_dest = gimple_goto_dest (stmt);
@@ -2927,6 +2989,9 @@ expand_FALLTHROUGH_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
}
else if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
;
+ else if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED
+ && gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
+ ;
else if (!is_gimple_debug (stmt))
/* Anything else is not expected. */
break;
@@ -6754,7 +6819,8 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
&& clear_padding_type_may_have_padding_p (type)
&& ((AGGREGATE_TYPE_P (type) && !cleared && !is_empty_ctor)
|| !AGGREGATE_TYPE_P (type))
- && is_var_need_auto_init (object))
+ && var_needs_auto_init_p (object)
+ && flag_auto_var_init != AUTO_INIT_CXX26)
gimple_add_padding_init_for_auto_var (object, false, pre_p);
return ret;
@@ -8461,6 +8527,7 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
if (init)
{
gimple_seq init_pre_p = NULL;
+ bool is_vla = false;
/* TARGET_EXPR temps aren't part of the enclosing block, so add it
to the temps list. Handle also variable length TARGET_EXPRs. */
@@ -8471,6 +8538,7 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
/* FIXME: this is correct only when the size of the type does
not depend on expressions evaluated in init. */
gimplify_vla_decl (temp, &init_pre_p);
+ is_vla = true;
}
else
{
@@ -8482,6 +8550,15 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
gimple_add_tmp_var (temp);
}
+ if (var_needs_auto_init_p (temp) && VOID_TYPE_P (TREE_TYPE (init)))
+ {
+ gimple_add_init_for_auto_var (temp, flag_auto_var_init, &init_pre_p);
+ if (flag_auto_var_init == AUTO_INIT_PATTERN
+ && !is_gimple_reg (temp)
+ && clear_padding_type_may_have_padding_p (TREE_TYPE (temp)))
+ gimple_add_padding_init_for_auto_var (temp, is_vla, &init_pre_p);
+ }
+
/* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the
expression is supposed to initialize the slot. */
if (VOID_TYPE_P (TREE_TYPE (init)))
diff --git a/gcc/ipa-split.cc b/gcc/ipa-split.cc
index 933ca16..48f6a72 100644
--- a/gcc/ipa-split.cc
+++ b/gcc/ipa-split.cc
@@ -1400,6 +1400,15 @@ split_function (basic_block return_bb, class split_point *split_point,
if (fndecl_built_in_p (node->decl))
set_decl_built_in_function (node->decl, NOT_BUILT_IN, 0);
+ /* Drop "clobber *this" attribute from first argument of the split
+ function if any. Code before that might be initializing the
+ members. */
+ if (tree arg = DECL_ARGUMENTS (node->decl))
+ if (lookup_attribute ("clobber *this", DECL_ATTRIBUTES (arg)))
+ DECL_ATTRIBUTES (arg)
+ = remove_attribute ("clobber *this",
+ copy_list (DECL_ATTRIBUTES (arg)));
+
/* If return_bb contains any clobbers that refer to SSA_NAMEs
set in the split part, remove them. Also reset debug stmts that
refer to SSA_NAMEs set in the split part. */
diff --git a/gcc/testsuite/c-c++-common/analyzer/invalid-shift-1.c b/gcc/testsuite/c-c++-common/analyzer/invalid-shift-1.c
index 08e5272..1b67c07 100644
--- a/gcc/testsuite/c-c++-common/analyzer/invalid-shift-1.c
+++ b/gcc/testsuite/c-c++-common/analyzer/invalid-shift-1.c
@@ -12,10 +12,10 @@ _dl_hwcaps_subdirs_build_bitmask (int subdirs, int active)
uint32_t mask;
if (subdirs != 32)
- mask = (1 << subdirs) - 1; /* { dg-message "shift by count \\('33'\\) >= precision of type \\('\[0-9\]+'\\)" } */
+ mask = (1 << subdirs) - 1; /* { dg-message "shift by count \\('33'\\) >= precision of type \\('\[0-9\]+'\\)" "" { xfail c++26 } } */
else
mask = -1;
- return mask ^ ((1U << inactive) - 1); /* { dg-message "shift by negative count \\('-1'\\)" } */
+ return mask ^ ((1U << inactive) - 1); /* { dg-message "shift by negative count \\('-1'\\)" "" { xfail c++26 } } */
}
void f1 (int);
diff --git a/gcc/testsuite/c-c++-common/goacc-gomp/nesting-1.c b/gcc/testsuite/c-c++-common/goacc-gomp/nesting-1.c
index 9ef154e..929dfca 100644
--- a/gcc/testsuite/c-c++-common/goacc-gomp/nesting-1.c
+++ b/gcc/testsuite/c-c++-common/goacc-gomp/nesting-1.c
@@ -1,10 +1,9 @@
-/* { dg-additional-options "--param=openacc-kernels=decompose" }
-
+/* { dg-additional-options "--param=openacc-kernels=decompose" } */
/* { dg-additional-options "-fopt-info-omp-note" } */
-
-/* { dg-additional-options "--param=openacc-privatization=noisy" }
- Prune a few: uninteresting, and potentially varying depending on GCC configuration (data types):
- { dg-prune-output {note: variable 'D\.[0-9]+' declared in block isn't candidate for adjusting OpenACC privatization level: not addressable} } */
+/* { dg-additional-options "--param=openacc-privatization=noisy" } */
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
+/* Prune a few: uninteresting, and potentially varying depending on GCC configuration (data types): */
+/* { dg-prune-output {note: variable 'D\.[0-9]+' declared in block isn't candidate for adjusting OpenACC privatization level: not addressable} } */
void
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-2.c b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-2.c
index 3ce9490..5aac40c 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-2.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-2.c
@@ -1,10 +1,13 @@
/* Test OpenACC 'kernels' construct decomposition. */
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
/* { dg-additional-options "-fopt-info-omp-all" } */
/* { dg-additional-options "--param=openacc-kernels=decompose" }
/* { dg-additional-options "-O2" } for 'parloops'. */
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
+
/* { dg-additional-options "--param=openacc-privatization=noisy" }
Prune a few: uninteresting, and potentially varying depending on GCC configuration (data types):
{ dg-prune-output {note: variable 'D\.[0-9]+' declared in block isn't candidate for adjusting OpenACC privatization level: not addressable} } */
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr100400-1-1.c b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr100400-1-1.c
index 57cb1a8..97fcaf7 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr100400-1-1.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr100400-1-1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
/* { dg-additional-options "--param openacc-kernels=decompose" } */
/* { dg-additional-options "-g0" } */
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr100400-1-3.c b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr100400-1-3.c
index 9779f10..f7c8069 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr100400-1-3.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr100400-1-3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
/* { dg-additional-options "--param openacc-kernels=decompose" } */
/* { dg-additional-options "-fchecking" }
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-1.c b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-1.c
index aa0fca7..5bb68c1 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-1.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
/* { dg-additional-options "--param openacc-kernels=decompose" } */
/* { dg-additional-options "-g0" } */
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-3.c b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-3.c
index 70c2ac5..43e1cca 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-3.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-3.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
/* { dg-additional-options "--param openacc-kernels=decompose" } */
/* { dg-additional-options "-fcompare-debug" } -- w/o debug compiled first.
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-4.c b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-4.c
index d1cc1a9..97d7bed 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-4.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104061-1-4.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
/* { dg-additional-options "--param openacc-kernels=decompose" } */
/* { dg-additional-options "-g -fcompare-debug" } -- w/ debug compiled first.
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104132-1.c b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104132-1.c
index 2a663e0..9094a57 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104132-1.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104132-1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
/* { dg-additional-options "--param openacc-kernels=decompose" } */
/* { dg-additional-options "-fopt-info-all-omp" } */
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104133-1.c b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104133-1.c
index 2724e22..aa5dd34 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104133-1.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104133-1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
/* { dg-additional-options "--param openacc-kernels=decompose" } */
/* { dg-additional-options "-fopt-info-all-omp" } */
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104774-1.c b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104774-1.c
index 3ef0c897..e6d4c55 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104774-1.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-decompose-pr104774-1.c
@@ -1,3 +1,4 @@
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
/* { dg-additional-options "--param openacc-kernels=decompose" } */
/* { dg-additional-options "-fopt-info-all-omp" } */
diff --git a/gcc/testsuite/c-c++-common/goacc/mdc-1.c b/gcc/testsuite/c-c++-common/goacc/mdc-1.c
index 923a4ea..8d3e7bf 100644
--- a/gcc/testsuite/c-c++-common/goacc/mdc-1.c
+++ b/gcc/testsuite/c-c++-common/goacc/mdc-1.c
@@ -3,6 +3,7 @@
/* TODO The tree dump scanning has certain expectations.
{ dg-do compile { target { lp64 || llp64 } } } */
+/* { dg-skip-if "PR121975" { c++26 } { "*" } { "" } } */
/* { dg-additional-options "-fdump-tree-omplower" } */
/* { dg-additional-options -Wuninitialized } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-1.c b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
index b29d904..0073514 100644
--- a/gcc/testsuite/c-c++-common/ubsan/vla-1.c
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
@@ -1,5 +1,5 @@
/* { dg-do run } */
-/* { dg-options "-fsanitize=vla-bound -Wall -Wno-unused-variable -fno-stack-clash-protection" } */
+/* { dg-options "-fsanitize=vla-bound -Wall -Wno-unused-variable -fno-stack-clash-protection -ftrivial-auto-var-init=uninitialized" } */
typedef long int V;
int x = -1;
diff --git a/gcc/testsuite/c-c++-common/uninit-17.c b/gcc/testsuite/c-c++-common/uninit-17.c
index b549536..5dd49a9 100644
--- a/gcc/testsuite/c-c++-common/uninit-17.c
+++ b/gcc/testsuite/c-c++-common/uninit-17.c
@@ -10,10 +10,10 @@ static void bar(int a, int *ptr)
do
{
int b;
- if (b < 40) {
+ if (b < 40) { /* { dg-warning "is used uninitialized" "" { target c++26 } } */
ptr[0] = b;
}
- b += 1; /* { dg-warning "is used uninitialized" } */
+ b += 1; /* { dg-warning "is used uninitialized" "" { target { c || c++23_down } } } */
ptr++;
}
while (--a != 0);
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-value-2.C b/gcc/testsuite/g++.dg/analyzer/exception-value-2.C
index ef9dd46..5173f538 100644
--- a/gcc/testsuite/g++.dg/analyzer/exception-value-2.C
+++ b/gcc/testsuite/g++.dg/analyzer/exception-value-2.C
@@ -1,3 +1,5 @@
+// { dg-skip-if "PR122044" { c++26 } { "*" } { "" } }
+
#include "../../gcc.dg/analyzer/analyzer-decls.h"
struct foo {};
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template18.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template18.C
new file mode 100644
index 0000000..e5e6e6a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template18.C
@@ -0,0 +1,11 @@
+// PR c++/122127
+// { dg-do compile { target c++11 } }
+
+template <int> struct resize;
+template <int _Np> using resize_t = resize<_Np>;
+template <class _Ap> struct basic_mask {
+ void _M_chunk() {
+ constexpr int __rem = 1;
+ [&] { resize_t<__rem>(); }();
+ }
+};
diff --git a/gcc/testsuite/g++.dg/cpp1y/vla-initlist1.C b/gcc/testsuite/g++.dg/cpp1y/vla-initlist1.C
index ba485df..ce35c90 100644
--- a/gcc/testsuite/g++.dg/cpp1y/vla-initlist1.C
+++ b/gcc/testsuite/g++.dg/cpp1y/vla-initlist1.C
@@ -1,5 +1,4 @@
// { dg-do run { target c++11 } }
-// { dg-skip-if "power overwrites two slots of array i" { "power*-*-*" } }
// { dg-options "-Wno-vla" }
#include <initializer_list>
@@ -7,7 +6,7 @@
struct A
{
int i;
- A(std::initializer_list<int>) { }
+ A(std::initializer_list<int>) : i{43} { }
A(int i): i{i} { }
~A() {}
};
@@ -18,7 +17,7 @@ int main(int argc, char **argv)
{ int i[x] = { 42, 42, 42, 42 }; }
{
A a[x] = { argc };
- if (a[1].i != 42)
+ if (a[1].i != 43)
__builtin_abort ();
}
}
diff --git a/gcc/testsuite/g++.dg/cpp26/attr-indeterminate1.C b/gcc/testsuite/g++.dg/cpp26/attr-indeterminate1.C
new file mode 100644
index 0000000..58f6dc5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/attr-indeterminate1.C
@@ -0,0 +1,154 @@
+// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
+// { dg-do compile { target c++11 } }
+
+int arr[2];
+struct S { int a, b; };
+S arr2[2];
+
+void
+foo ([[indeterminate]] int n, int n2 [[indeterminate]], int n3 [[indeterminate]] [2])
+{
+ [[indeterminate]] int x1, x11, x12, x13;
+ int x14, x15 [[indeterminate]];
+ [[indeterminate ("foobar")]] int x2; // { dg-error "'indeterminate' attribute does not take any arguments" }
+ // { dg-error "expected primary-expression before 'int'" "" { target *-*-* } .-1 }
+ [[indeterminate (0)]] int x3; // { dg-error "'indeterminate' attribute does not take any arguments" }
+ // { dg-error "expected primary-expression before 'int'" "" { target *-*-* } .-1 }
+ [[indeterminate ("foo", "bar", "baz")]] int x4;// { dg-error "'indeterminate' attribute does not take any arguments" }
+ // { dg-error "expected primary-expression before 'int'" "" { target *-*-* } .-1 }
+ [[indeterminate (0, 1, 2)]] int x5; // { dg-error "'indeterminate' attribute does not take any arguments" }
+ // { dg-error "expected primary-expression before 'int'" "" { target *-*-* } .-1 }
+
+ auto a = [] [[indeterminate]] () {}; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ auto b = [] constexpr [[indeterminate]] {}; // { dg-warning "'indeterminate' attribute does not apply to types" }
+ // { dg-error "parameter declaration before lambda declaration specifiers only optional with" "" { target c++20_down } .-1 }
+ // { dg-error "'constexpr' lambda only available with" "" { target c++14_down } .-2 }
+ auto c = [] noexcept [[indeterminate]] {}; // { dg-warning "'indeterminate' attribute does not apply to types" }
+ // { dg-error "parameter declaration before lambda exception specification only optional with" "" { target c++20_down } .-1 }
+ auto d = [] () [[indeterminate]] {}; // { dg-warning "'indeterminate' attribute does not apply to types" }
+ auto e = new int [n] [[indeterminate]]; // { dg-warning "attributes ignored on outermost array type in new expression" }
+ auto e2 = new int [n] [[indeterminate]] [42]; // { dg-warning "attributes ignored on outermost array type in new expression" }
+ auto f = new int [n][42] [[indeterminate]]; // { dg-warning "'indeterminate' attribute does not apply to types" }
+ [[indeterminate]]; // { dg-warning "attributes at the beginning of statement are ignored" }
+ [[indeterminate]] {} // { dg-warning "attributes at the beginning of statement are ignored" }
+ [[indeterminate]] if (true) {} // { dg-warning "attributes at the beginning of statement are ignored" }
+ [[indeterminate]] while (false) {} // { dg-warning "attributes at the beginning of statement are ignored" }
+ [[indeterminate]] goto lab; // { dg-warning "attributes at the beginning of statement are ignored" }
+ [[indeterminate]] lab:; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ [[indeterminate]] try {} catch (int) {} // { dg-warning "attributes at the beginning of statement are ignored" }
+ if ([[indeterminate]] int x = 0) {}
+ switch (n)
+ {
+ [[indeterminate]] case 1: // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ [[indeterminate]] break; // { dg-warning "attributes at the beginning of statement are ignored" }
+ [[indeterminate]] default: // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ break;
+ }
+ for ([[indeterminate]] auto a : arr) {}
+ for ([[indeterminate]] auto [a, b] : arr2) {} // { dg-error "structured bindings only available with" "" { target c++14_down } }
+ [[indeterminate]] asm (""); // { dg-warning "attributes ignored on 'asm' declaration" }
+ try {} catch ([[indeterminate]] int x) {}
+ try {} catch ([[indeterminate]] int) {}
+ try {} catch (int [[indeterminate]] x) {} // { dg-warning "attribute ignored" }
+ try {} catch (int [[indeterminate]]) {} // { dg-warning "attribute ignored" }
+ try {} catch (int x [[indeterminate]]) {}
+}
+
+[[indeterminate]] int bar (); // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+using foobar [[indeterminate]] = int; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+[[indeterminate]] int a; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+[[indeterminate]] auto [b, c] = arr; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ // { dg-error "structured bindings only available with" "" { target c++14_down } .-1 }
+[[indeterminate]]; // { dg-warning "attribute ignored" }
+inline [[indeterminate]] void baz () {} // { dg-warning "attribute ignored" }
+ // { dg-error "standard attributes in middle of decl-specifiers" "" { target *-*-* } .-1 }
+constexpr [[indeterminate]] int qux () { return 0; } // { dg-warning "attribute ignored" }
+ // { dg-error "standard attributes in middle of decl-specifiers" "" { target *-*-* } .-1 }
+int [[indeterminate]] d; // { dg-warning "attribute ignored" }
+int const [[indeterminate]] e = 1; // { dg-warning "attribute ignored" }
+struct A {} [[indeterminate]]; // { dg-warning "attribute ignored in declaration of 'struct A'" }
+struct A [[indeterminate]]; // { dg-warning "attribute ignored" }
+struct A [[indeterminate]] a1; // { dg-warning "attribute ignored" }
+A [[indeterminate]] a2; // { dg-warning "attribute ignored" }
+enum B { B0 } [[indeterminate]]; // { dg-warning "attribute ignored in declaration of 'enum B'" }
+enum B [[indeterminate]]; // { dg-warning "attribute ignored" }
+enum B [[indeterminate]] b1; // { dg-warning "attribute ignored" }
+B [[indeterminate]] b2; // { dg-warning "attribute ignored" }
+struct [[indeterminate]] C {}; // { dg-warning "'indeterminate' attribute does not apply to types" }
+int f [[indeterminate]]; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+int g[2] [[indeterminate]]; // { dg-warning "'indeterminate' attribute does not apply to types" }
+int g2 [[indeterminate]] [2]; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+int corge () [[indeterminate]]; // { dg-warning "'indeterminate' attribute does not apply to types" }
+int *[[indeterminate]] h; // { dg-warning "'indeterminate' attribute does not apply to types" }
+int & [[indeterminate]] i = f; // { dg-warning "'indeterminate' attribute does not apply to types" }
+int && [[indeterminate]] j = 0; // { dg-warning "'indeterminate' attribute does not apply to types" }
+int S::* [[indeterminate]] k; // { dg-warning "'indeterminate' attribute does not apply to types" }
+auto l = sizeof (int [2] [[indeterminate]]); // { dg-warning "'indeterminate' attribute does not apply to types" }
+int freddy ([[indeterminate]] int a,
+ [[indeterminate]] int,
+ [[indeterminate]] int c = 0,
+ [[indeterminate]] int = 0);
+void
+corge ([[indeterminate]] int a,
+ [[indeterminate]] int,
+ [[indeterminate]] int c = 0,
+ [[indeterminate]] int = 0)
+{
+}
+[[indeterminate]] void
+garply () // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+{
+}
+int grault (int [[indeterminate]] a, // { dg-warning "attribute ignored" }
+ int [[indeterminate]], // { dg-warning "attribute ignored" }
+ int [[indeterminate]] c = 0, // { dg-warning "attribute ignored" }
+ int [[indeterminate]] = 0); // { dg-warning "attribute ignored" }
+void
+waldo (int [[indeterminate]] a, // { dg-warning "attribute ignored" }
+ int [[indeterminate]], // { dg-warning "attribute ignored" }
+ int [[indeterminate]] c = 0, // { dg-warning "attribute ignored" }
+ int [[indeterminate]] = 0) // { dg-warning "attribute ignored" }
+{
+}
+int plugh (int a [[indeterminate]],
+ int b [[indeterminate]] = 0);
+void
+thud (int a [[indeterminate]],
+ int b [[indeterminate]] = 0)
+{
+}
+enum [[indeterminate]] D { D0 }; // { dg-warning "'indeterminate' attribute does not apply to types" }
+enum class [[indeterminate]] E { E0 }; // { dg-warning "'indeterminate' attribute does not apply to types" }
+enum F {};
+enum [[indeterminate]] F; // { dg-warning "'indeterminate' attribute does not apply to types" }
+enum G {
+ G0 [[indeterminate]], // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ G1 [[indeterminate]] = 2 // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+};
+namespace [[indeterminate]] H { using H0 = int; }// { dg-warning "'indeterminate' attribute directive ignored" }
+namespace [[indeterminate]] {} // { dg-warning "'indeterminate' attribute directive ignored" }
+[[indeterminate]] using namespace H; // { dg-warning "'indeterminate' attribute directive ignored" }
+struct [[indeterminate]] I // { dg-warning "'indeterminate' attribute does not apply to types" }
+{
+ [[indeterminate]]; // { dg-error "declaration does not declare anything" }
+ [[indeterminate]] int i; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ [[indeterminate]] int foo (); // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ [[indeterminate]] int bar () { return 1; } // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ [[indeterminate]] int : 0; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ [[indeterminate]] int i2 : 5; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ [[indeterminate]] static int i3; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+ static int i4;
+};
+[[indeterminate]] int I::i4 = 0; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+struct J : [[indeterminate]] C {}; // { dg-warning "attributes on base specifiers are ignored" }
+#if __cpp_concepts >= 201907L
+template <typename T>
+concept K [[indeterminate]] = requires { true; };// { dg-error "'indeterminate' on declaration other than parameter or automatic variable" "" { target c++20 } }
+#endif
+typedef int L [[indeterminate]]; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
+template <typename T>
+struct M {};
+template <>
+struct [[indeterminate]] M<int> { int m; }; // { dg-warning "'indeterminate' attribute does not apply to types" }
+typedef int N[2] [[indeterminate]]; // { dg-warning "'indeterminate' attribute does not apply to types" }
+typedef int O [[indeterminate]] [2]; // { dg-error "'indeterminate' on declaration other than parameter or automatic variable" }
diff --git a/gcc/testsuite/g++.dg/cpp26/attr-indeterminate2.C b/gcc/testsuite/g++.dg/cpp26/attr-indeterminate2.C
new file mode 100644
index 0000000..a2704c6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/attr-indeterminate2.C
@@ -0,0 +1,39 @@
+// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fdump-tree-gimple" }
+// { dg-skip-if "" { c++26 } { "-ftrivial-auto-var-init=*" } { "" } }
+// Expect .DEFERRED_INIT calls for the h, r and s variables (3) and
+// temporaries for the second arguments to foo and baz calls (4).
+// { dg-final { scan-tree-dump-times " = \\.DEFERRED_INIT \\\(" 7 "gimple" { target c++26 } } }
+
+struct S { S (); S (const S &); ~S (); int s; };
+void foo (S a [[indeterminate]], S b, S c [[indeterminate]] = S ());
+void foo (S d, S e, S f [[indeterminate]]);
+
+void
+bar ()
+{
+ S g [[indeterminate]], h;
+ foo (g, h, S ());
+ foo (g, h);
+}
+
+void
+foo (S i [[indeterminate]], S j, S k)
+{
+}
+
+void
+baz ([[indeterminate]] S l, S m, [[indeterminate]] S n = S ())
+{
+}
+
+void baz (S o, S p, S q);
+
+void
+qux ()
+{
+ S r, s;
+ baz (r, s, s);
+ baz (r, s);
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/attr-indeterminate3.C b/gcc/testsuite/g++.dg/cpp26/attr-indeterminate3.C
new file mode 100644
index 0000000..8f13390
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/attr-indeterminate3.C
@@ -0,0 +1,21 @@
+// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
+// { dg-do compile { target c++11 } }
+// { dg-skip-if "" { c++26 } { "-ftrivial-auto-var-init=*" } { "" } }
+
+struct S { S (); S (const S &); ~S (); int s; };
+void foo (S u, S v [[indeterminate]], int);
+void foo (S a, S b, S c = S ()); // { dg-message "earlier declaration" }
+void foo (S d, S e, S f [[indeterminate]]); // { dg-error "'indeterminate' attribute not specified for parameter 'f' on the first declaration of its function" }
+
+void
+foo (S i [[indeterminate]], S j, S k) // { dg-error "'indeterminate' attribute not specified for parameter 'i' on the first declaration of its function" }
+{
+}
+
+void
+bar (S l, S m, S n = S ()) // { dg-message "earlier declaration" }
+{
+}
+
+void bar (S o [[indeterminate]], S p, [[indeterminate]]S q); // { dg-error "'indeterminate' attribute not specified for parameter 'o' on the first declaration of its function" }
+ // { dg-error "'indeterminate' attribute not specified for parameter 'q' on the first declaration of its function" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp26/attr-indeterminate4.C b/gcc/testsuite/g++.dg/cpp26/attr-indeterminate4.C
new file mode 100644
index 0000000..946e019
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/attr-indeterminate4.C
@@ -0,0 +1,36 @@
+// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" }
+// { dg-final { scan-tree-dump-not " = \\.DEFERRED_INIT \\\(" "gimple" } }
+
+struct S { S (); S (const S &); ~S (); int s; };
+void foo (S a [[indeterminate]], S b, S c [[indeterminate]] = S ());
+void foo (S d, S e, S f [[indeterminate]]);
+
+void
+bar ()
+{
+ S g [[indeterminate]], h;
+ foo (g, h, S ());
+ foo (g, h);
+}
+
+void
+foo (S i [[indeterminate]], S j, S k)
+{
+}
+
+void
+baz ([[indeterminate]] S l, S m, [[indeterminate]] S n = S ())
+{
+}
+
+void baz (S o, S p, S q);
+
+void
+qux ()
+{
+ S r, s;
+ baz (r, s, s);
+ baz (r, s);
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/erroneous1.C b/gcc/testsuite/g++.dg/cpp26/erroneous1.C
new file mode 100644
index 0000000..78769e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/erroneous1.C
@@ -0,0 +1,61 @@
+// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
+// { dg-do run { target c++26 } }
+// { dg-skip-if "" { *-*-* } { "-ftrivial-auto-var-init=*" } { "" } }
+// { dg-options "-O2 -Wuninitialized" }
+
+#define assert(x) if (!(x)) __builtin_abort ()
+
+template <typename T>
+[[gnu::noipa]] T
+baz (T &x)
+{
+ return x;
+}
+
+[[gnu::noipa]] int
+foo (bool b)
+{
+ unsigned char c;
+ unsigned char d = c; // no erroneous behavior, but d has an erroneous value
+ // { dg-warning "'c' is used uninitialized" "" { target *-*-* } .-1 }
+
+ assert (c == d); // holds, both integral promotions have erroneous behavior
+
+ unsigned char f = c;
+ unsigned char g = baz (f);
+
+ assert (g == c);
+
+ int e = d; // erroneous behavior
+ baz (e);
+ return b ? d : 0; // erroneous behavior if b is true
+}
+
+[[gnu::noipa]] void
+bar ()
+{
+ int d1, d2;
+
+ int e1 = d1; // erroneous behavior
+ int e2 = d1; // erroneous behavior
+
+ assert (e1 == e2); // holds
+ assert (e1 == d1); // holds, erroneous behavior
+ assert (e2 == d1); // holds, erroneous behavior
+
+ int f = d1; // { dg-warning "'d1' is used uninitialized" }
+ int g = baz (f);
+ assert (g == d1);
+
+ __builtin_memcpy (&d2, &d1, sizeof (int)); // no erroneous behavior, but d2 has an erroneous value
+ assert (e1 == d2); // holds, erroneous behavior
+ assert (e2 == d2); // holds, erroneous behavior
+}
+
+int
+main ()
+{
+ foo (false);
+ foo (true);
+ bar ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/erroneous2.C b/gcc/testsuite/g++.dg/cpp26/erroneous2.C
new file mode 100644
index 0000000..e8c66f4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/erroneous2.C
@@ -0,0 +1,234 @@
+// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
+// { dg-do compile }
+// { dg-skip-if "" { *-*-* } { "-ftrivial-auto-var-init=*" } { "" } }
+// { dg-options "-O2 -fdump-tree-gimple" }
+// All the s1..s24 variables and i1 need .DEFERRED_INIT call on their
+// declarations.
+// Plus, forward gotos to l1 & l2 labels need up to s1-s4 and s6-s9 vars to
+// be .DEFERRED_INITed (and backward gotos up to that minus the first two).
+// switch to case 15 skips over s12, switch to case 16/17 skip
+// over s12 and s13 but the adjacent l3 label needs to also skip over s3-s4
+// and s6-s9 and s11. switch to case 18 skips over s12-s14 and switch to
+// default in the same switch skips over s12-s15.
+// goto l4; skips over s19 initialization.
+// goto l5; skips over s20-s22 initialization.
+// switch to case 32/33 skips over s23 but goto to adjacent l6 skips also
+// over s20-s22. switch to default in that switch skips over s23-s24.
+// { dg-final { scan-tree-dump-times " s1 = \.DEFERRED_INIT \\\(" 2 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s2 = \.DEFERRED_INIT \\\(" 2 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s3 = \.DEFERRED_INIT \\\(" 3 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s4 = \.DEFERRED_INIT \\\(" 3 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s5 = \.DEFERRED_INIT \\\(" 1 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s6 = \.DEFERRED_INIT \\\(" 3 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s7 = \.DEFERRED_INIT \\\(" 3 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s8 = \.DEFERRED_INIT \\\(" 3 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s9 = \.DEFERRED_INIT \\\(" 3 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s10 = \.DEFERRED_INIT \\\(" 1 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s11 = \.DEFERRED_INIT \\\(" 2 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s12 = \.DEFERRED_INIT \\\(" 5 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s13 = \.DEFERRED_INIT \\\(" 4 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s14 = \.DEFERRED_INIT \\\(" 3 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s15 = \.DEFERRED_INIT \\\(" 2 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s16 = \.DEFERRED_INIT \\\(" 1 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s17 = \.DEFERRED_INIT \\\(" 1 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s18 = \.DEFERRED_INIT \\\(" 1 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s19 = \.DEFERRED_INIT \\\(" 2 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s20 = \.DEFERRED_INIT \\\(" 3 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s21 = \.DEFERRED_INIT \\\(" 3 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s22 = \.DEFERRED_INIT \\\(" 3 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s23 = \.DEFERRED_INIT \\\(" 3 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " s24 = \.DEFERRED_INIT \\\(" 2 "gimple" { target c++26 } } }
+// { dg-final { scan-tree-dump-times " i1 = \.DEFERRED_INIT \\\(" 1 "gimple" { target c++26 } } }
+
+struct S { int a, b, c; };
+
+int
+foo (int x)
+{
+ int r = 0;
+ if (x == 1)
+ goto l1;
+ S s1;
+ if (x == 2)
+ goto l1;
+ S s2;
+ {
+ S s10;
+ if (x == 12)
+ goto l1;
+ s10.a = 1;
+ r += s10.a;
+ int i1;
+ if (x == 13)
+ goto l1;
+ i1 = 2;
+ r += i1;
+ }
+ if (x == 3)
+ goto l2;
+ if (x == 4)
+ goto l1;
+ {
+ S s3;
+ if (x == 5)
+ goto l2;
+ S s4;
+ if (x == 6)
+ goto l1;
+ {
+ S s5;
+ if (x == 7)
+ goto l1;
+ s5.a = 5;
+ r += s5.a;
+ }
+ S s6;
+ {
+ S s7;
+ S s8;
+ if (x == 8)
+ goto l1;
+ S s9;
+ if (x == 9)
+ goto l2;
+ if (x == 10)
+ goto l2;
+ if (x == 11)
+ goto l2;
+ l1:
+ l2:
+ s1.a = 1;
+ s2.b = 2;
+ s3.c = 3;
+ s4.a = 4;
+ s6.b = 6;
+ s7.c = 7;
+ s8.a = 8;
+ s9.b = 9;
+ r += s1.a + s2.b + s3.c;
+ r += s4.a + s6.b + s7.c;
+ r += s8.a + s9.b;
+ if (x == 14)
+ goto l3;
+ S s11;
+ switch (x)
+ {
+ S s12;
+ case 15:
+ S s13;
+ // FALLTHRU
+ l3:
+ case 16:
+ case 17:
+ S s14;
+ s11.a = 1;
+ s12.b = 2;
+ s13.c = 3;
+ s14.a = 4;
+ r += s11.a + s12.b + s13.c;
+ r += s14.a;
+ return r;
+ case 18:
+ S s15;
+ s11.a = 1;
+ s12.b = 2;
+ s13.c = 3;
+ s14.a = 4;
+ s15.b = 5;
+ r += s11.a + s12.b + s13.c;
+ r += s14.a + s15.b;
+ return r;
+ default:
+ if (x != 19 && x != 20)
+ break;
+ S s16;
+ s11.a = 1;
+ s12.b = 2;
+ s13.c = 3;
+ s14.a = 4;
+ s15.b = 5;
+ s16.c = 6;
+ r += s11.a + s12.b + s13.c;
+ r += s14.a + s15.b + s16.c;
+ return r;
+ }
+ if (x == 21)
+ goto l3;
+ }
+ S s17;
+ if (x == 22)
+ goto l3;
+ if (x == 23)
+ goto l1;
+ if (x == 24)
+ goto l2;
+ s17.a = 1;
+ r += s17.a;
+ }
+ S s18;
+ if (x == 25)
+ {
+ S s19;
+ s19.c = 2;
+ r += s19.c;
+ if (x == 29)
+ l4:;
+ goto l3;
+ }
+ if (x == 26)
+ goto l1;
+ if (x == 27)
+ goto l2;
+ s18.b = 1;
+ r += s18.b;
+ if (x == 28)
+ goto l4;
+ {
+ S s20;
+ {
+ S s21;
+ if (x == 29)
+ goto l1;
+ S s22;
+ if (x == 30)
+ goto l2;
+ l5:
+ s20.a = 1;
+ s21.b = 2;
+ s22.c = 3;
+ r += s20.a + s21.b + s22.c;
+ switch (x)
+ {
+ case 31:
+ S s23;
+ // FALLTHRU
+ l6:
+ case 32:
+ case 33:
+ S s24;
+ s23.a = 1;
+ s24.b = 2;
+ r += s23.a + s24.b;
+ return r;
+ default:
+ if (x >= 34 && x <= 35)
+ return r;
+ break;
+ }
+ if (x == 34)
+ goto l5;
+ if (x == 35)
+ goto l6;
+ return r;
+ }
+ if (x == 36)
+ goto l5;
+ if (x == 37)
+ goto l6;
+ }
+ if (x == 38)
+ goto l5;
+ if (x == 39)
+ goto l6;
+ return r;
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/erroneous3.C b/gcc/testsuite/g++.dg/cpp26/erroneous3.C
new file mode 100644
index 0000000..d48a08e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/erroneous3.C
@@ -0,0 +1,158 @@
+// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wimplicit-fallthrough -Wswitch-unreachable" }
+// Make sure -Wimplicit-fallthrough and -Wswitch-unreachable
+// are consistent between -std=c++23 and -std=c++26 even when
+// the latter instruments jumps across vacuous initializations.
+
+int i;
+
+void
+foo (int x)
+{
+ switch (x)
+ {
+ case 1:
+ int j;
+ ++i; // { dg-warning "this statement may fall through" }
+ case 2: // { dg-message "here" }
+ int k;
+ ++i;
+ // FALLTHRU
+ case 3:
+ int l;
+ ++i;
+ [[fallthrough]];
+ default:
+ int m;
+ ++i;
+ j = 42;
+ k = 42;
+ l = 42;
+ m = 42;
+ i += (j - k) + (l - m);
+ break;
+ }
+}
+
+void
+bar (int x)
+{
+ if (x == 6)
+ goto l1;
+ if (x == 7)
+ goto l2;
+ if (x == 8)
+ goto l3;
+ if (x == 9)
+ goto l4;
+ if (x == 10)
+ goto l5;
+ if (x == 11)
+ goto l6;
+ int j;
+ j = 5;
+ i += j;
+ switch (x)
+ {
+ case 1:
+ l1:
+ ++i; // { dg-warning "this statement may fall through" }
+ case 2: // { dg-message "here" }
+ l2:
+ ++i;
+ // FALLTHRU
+ case 3:
+ l3:
+ ++i;
+ [[fallthrough]];
+ default:
+ l4:
+ ++i;
+ break;
+ case 4:
+ ++i; // { dg-warning "this statement may fall through" }
+ case 5: // { dg-message "here" }
+ l5:;
+ ++i; // { dg-warning "this statement may fall through" }
+ case 6: // { dg-message "here" }
+ ++i;
+ case 7:
+ l6:;
+ }
+}
+
+void
+baz (int x)
+{
+ switch (x)
+ {
+ case 1:
+ int j [[indeterminate]];
+ ++i; // { dg-warning "this statement may fall through" }
+ case 2: // { dg-message "here" }
+ int k [[indeterminate]];
+ ++i;
+ // FALLTHRU
+ case 3:
+ int l [[indeterminate]];
+ ++i;
+ [[fallthrough]];
+ default:
+ int m [[indeterminate]];
+ ++i;
+ j = 42;
+ k = 42;
+ l = 42;
+ m = 42;
+ i += (j - k) + (l - m);
+ break;
+ }
+}
+
+void
+qux (int x)
+{
+ if (x == 6)
+ goto l1;
+ if (x == 7)
+ goto l2;
+ if (x == 8)
+ goto l3;
+ if (x == 9)
+ goto l4;
+ if (x == 10)
+ goto l5;
+ if (x == 11)
+ goto l6;
+ int j [[indeterminate]];
+ j = 5;
+ i += j;
+ switch (x)
+ {
+ case 1:
+ l1:
+ ++i; // { dg-warning "this statement may fall through" }
+ case 2: // { dg-message "here" }
+ l2:
+ ++i;
+ // FALLTHRU
+ case 3:
+ l3:
+ ++i;
+ [[fallthrough]];
+ default:
+ l4:
+ ++i;
+ break;
+ case 4:
+ ++i; // { dg-warning "this statement may fall through" }
+ case 5: // { dg-message "here" }
+ l5:;
+ ++i; // { dg-warning "this statement may fall through" }
+ case 6: // { dg-message "here" }
+ ++i;
+ case 7:
+ l6:;
+ }
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/erroneous4.C b/gcc/testsuite/g++.dg/cpp26/erroneous4.C
new file mode 100644
index 0000000..0863480
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/erroneous4.C
@@ -0,0 +1,37 @@
+// C++ 26 P2795R5 - Erroneous behaviour for uninitialized reads
+// { dg-do compile { target c++23 } }
+// Make sure we don't reject this in C++26 because of
+// .DEFERRED_INIT calls.
+
+constexpr int
+foo (int x)
+{
+ if (x == 6)
+ goto l1;
+ if (x == 7)
+ goto l2;
+ int i;
+ switch (x)
+ {
+ int j;
+ case 1:
+ i = 6;
+ return i;
+ case 2:
+ i = 4;
+ l1:
+ i = 5;
+ return i;
+ case 3:
+ l2:
+ i = 7;
+ return i;
+ default:
+ return 42;
+ }
+}
+
+static_assert (foo (1) == 6);
+static_assert (foo (2) == 5);
+static_assert (foo (3) == 7);
+static_assert (foo (4) == 42);
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new28.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new28.C
new file mode 100644
index 0000000..7828f30
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new28.C
@@ -0,0 +1,45 @@
+// PR c++/115645
+// { dg-do compile { target c++20 } }
+
+using size_t = decltype(sizeof(0));
+
+void* operator new(size_t, void* p) { return p; }
+void* operator new[](size_t, void* p) { return p; }
+
+#define VERIFY(C) if (!(C)) throw
+
+namespace std {
+ template<typename T>
+ constexpr T* construct_at(T* p)
+ {
+ if constexpr (__is_array(T))
+ return ::new((void*)p) T[1]();
+ else
+ return ::new((void*)p) T();
+ }
+}
+
+struct S {
+ constexpr S () : s (0) {}
+ constexpr S (int x) : s (x) {}
+ constexpr bool operator== (int x) const { return s == x; }
+ int s;
+};
+
+constexpr void
+test_array()
+{
+ S arr[1] { 99 };
+ std::construct_at(&arr);
+ VERIFY( arr[0] == 0 );
+
+ union U {
+ long long x = -1;
+ S arr[4];
+ } u;
+
+ auto p = std::construct_at(&u.arr);
+ VERIFY( (*p)[0] == 0 );
+}
+
+static_assert( [] { test_array(); return true; }() );
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new29.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new29.C
new file mode 100644
index 0000000..368018d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new29.C
@@ -0,0 +1,30 @@
+// P0784R7
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-fdelete-null-pointer-checks" }
+
+struct S
+{
+ constexpr S () : s (0) { s++; }
+ constexpr S (int x) : s (x) { s += 2; }
+ constexpr ~S () { if (s != 35) asm (""); s = 5; }
+ int s;
+};
+
+constexpr bool
+foo (int n)
+{
+ S *p = new S (7);
+ if (p->s != 9) return false;
+ p->s = 35;
+ delete p;
+ p = new S[n] { 11, 13, 15 };
+ if (p[0].s != 13 || p[1].s != 15 || p[2].s != 17) return false;
+ p[0].s = 35;
+ p[2].s = 35;
+ p[1].s = 35;
+ delete[] p;
+ return true;
+}
+
+constexpr bool a = foo (3);
+static_assert (a);
diff --git a/gcc/testsuite/g++.dg/modules/adl-6_c.C b/gcc/testsuite/g++.dg/modules/adl-6_c.C
index 99b6c4c..2c675f5 100644
--- a/gcc/testsuite/g++.dg/modules/adl-6_c.C
+++ b/gcc/testsuite/g++.dg/modules/adl-6_c.C
@@ -1,5 +1,5 @@
// PR c++/117658
-// { dg-additional-options "-fmodules" }
+// { dg-additional-options "-fmodules -Wno-error=external-tu-local" }
import N;
@@ -22,7 +22,8 @@ void test() {
apply_err(x); // error: R::g has internal linkage and cannot be used outside N
// { dg-message "here" "" { target *-*-* } .-1 }
- // { dg-error "'g'" "" { target *-*-* } 0 }
+ // { dg-warning "lookup of 'R::g'" "" { target *-*-* } 0 }
+ // { dg-error "'g' was not declared" "" { target *-*-* } 0 }
auto y = make_Y();
f(y); // OK, I::B::f and I::A::Y have matching innermost non-inline namespace
diff --git a/gcc/testsuite/g++.dg/modules/internal-14_c.C b/gcc/testsuite/g++.dg/modules/internal-14_c.C
index 4f8e785c..50fb8e6 100644
--- a/gcc/testsuite/g++.dg/modules/internal-14_c.C
+++ b/gcc/testsuite/g++.dg/modules/internal-14_c.C
@@ -4,6 +4,6 @@
import m;
int main() {
- // { dg-error "instantiation exposes TU-local entity '(fun1|Dodgy)'" "" { target *-*-* } 0 }
+ // { dg-error "instantiation exposes TU-local entity '\[^']*(fun1|Dodgy)\[^']*'" "" { target *-*-* } 0 }
fun2(123); // { dg-message "required from here" }
}
diff --git a/gcc/testsuite/g++.dg/modules/internal-15_a.C b/gcc/testsuite/g++.dg/modules/internal-15_a.C
new file mode 100644
index 0000000..03fec2a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-15_a.C
@@ -0,0 +1,28 @@
+// { dg-additional-options "-fmodules -fdump-lang-module-graph -Wno-global-module" }
+// { dg-module-cmi A }
+
+export module A;
+
+namespace N {
+ struct A {};
+ void adl(A);
+ inline namespace inner {
+ static void adl(int);
+ }
+}
+namespace G {
+ struct B {};
+ void adl(B);
+ namespace {
+ extern "C++" void adl(int);
+ }
+}
+void adl(double);
+
+template <typename T>
+inline void h(T t) {
+ adl(t);
+}
+
+// { dg-final { scan-lang-dump {Binding on tu-local function_decl:'::N::inner::adl' found} module } }
+// { dg-final { scan-lang-dump-not {'G::_GLOBAL__N_1::adl'} module } }
diff --git a/gcc/testsuite/g++.dg/modules/internal-15_b.C b/gcc/testsuite/g++.dg/modules/internal-15_b.C
new file mode 100644
index 0000000..003d948
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-15_b.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules -pedantic-errors" }
+
+module A;
+
+void other() {
+ adl(N::A{}); // OK, lookup occurs from here
+ h(0); // OK, doesn't consider N::inner::adl
+
+ h(N::A{}); // { dg-message "required from here" }
+ // { dg-error "TU-local" "" { target *-*-* } 0 }
+
+ h(G::B{}); // OK, G::adl is not attached to A
+}
diff --git a/gcc/testsuite/g++.dg/opt/store-merging-1.C b/gcc/testsuite/g++.dg/opt/store-merging-1.C
index c7f294e..8c46252 100644
--- a/gcc/testsuite/g++.dg/opt/store-merging-1.C
+++ b/gcc/testsuite/g++.dg/opt/store-merging-1.C
@@ -1,7 +1,7 @@
// PR target/92038
// { dg-do compile { target int32 } }
// { dg-require-effective-target store_merge }
-// { dg-options "-O2 -flifetime-dse=2 -fdump-tree-store-merging-details" }
+// { dg-options "-O2 -flifetime-dse=2 -fdump-tree-store-merging-details -ftrivial-auto-var-init=uninitialized" }
// { dg-final { scan-tree-dump "New sequence of \[12] stores to replace old one of 2 stores" "store-merging" } }
struct S { S () : a (0), b (0) {} int a; char b; char c[3]; };
diff --git a/gcc/testsuite/g++.dg/parse/auto-struct-param.C b/gcc/testsuite/g++.dg/parse/auto-struct-param.C
new file mode 100644
index 0000000..78573c6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/auto-struct-param.C
@@ -0,0 +1,4 @@
+// PR c++/122112
+// { dg-do compile { target c++20 } }
+
+void func(struct { auto x; }); // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/uninit-pred-loop-1_b.C b/gcc/testsuite/g++.dg/uninit-pred-loop-1_b.C
index b17b936..55b15b7 100644
--- a/gcc/testsuite/g++.dg/uninit-pred-loop-1_b.C
+++ b/gcc/testsuite/g++.dg/uninit-pred-loop-1_b.C
@@ -13,7 +13,7 @@ int foo(int n)
_err;
});
- if (err == 0) return 17;
+ if (err == 0) return 17; /* { dg-warning "'_err' may be used uninitialized" "" { target c++26 } } */
}
return 18;
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-20.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-20.C
index 36f8046..643e801 100644
--- a/gcc/testsuite/g++.dg/warn/Warray-bounds-20.C
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-20.C
@@ -26,7 +26,7 @@ struct D1: virtual B, virtual C
/* The warning would ideally point to the assignment but instead points
to the opening brace. */
D1 ()
- { // { dg-warning "\\\[-Warray-bounds" "brace" }
+ {
ci = 0; // { dg-warning "\\\[-Warray-bounds" "assign" { xfail lp64 } }
}
};
@@ -35,11 +35,11 @@ void sink (void*);
void warn_derived_ctor_access_new_decl ()
{
- char a[sizeof (D1)]; // { dg-message "at offset 1 into object 'a' of size 40" "LP64 note" { target lp64} }
- // { dg-message "at offset 1 into object 'a' of size 20" "LP64 note" { target ilp32} .-1 }
+ char a[sizeof (D1)]; // { dg-message "at offset 1 into object 'a' of size 40" "LP64 note" { target lp64 } }
+ // { dg-message "at offset 1 into object 'a' of size 20" "LP32 note" { target ilp32 } .-1 }
char *p = a;
++p;
- D1 *q = new (p) D1; // { dg-warning "-Warray-bounds" }
+ D1 *q = new (p) D1; // { dg-warning "\\\[-Warray-bounds" }
sink (q);
}
@@ -47,14 +47,14 @@ void warn_derived_ctor_access_new_alloc ()
{
char *p = (char*)operator new (sizeof (D1)); // { dg-message "at offset 1 into object of size \\d+ allocated by '\[^\n\r]*operator new\[^\n\r]*'" "note" }
++p;
- D1 *q = new (p) D1; // { dg-warning "-Warray-bounds" }
+ D1 *q = new (p) D1; // { dg-warning "\\\[-Warray-bounds" }
sink (q);
}
void warn_derived_ctor_access_new_array_decl ()
{
char b[sizeof (D1) * 2]; // { dg-message "at offset \\d+ into object 'b' of size 80" "LP64 note" { target { lp64 } xfail { lp64 } } }
- // { dg-message "at offset \\d+ into object 'b' of size 40" "LP64 note" { target { ilp32 } xfail { ilp32 } } .-1 }
+ // { dg-message "at offset \\d+ into object 'b' of size 40" "LP32 note" { target { ilp32 } xfail { ilp32 } } .-1 }
char *p = b;
++p;
D1 *q = new (p) D1[2];
diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-13.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-13.C
index b74a2fa..47a7545 100644
--- a/gcc/testsuite/g++.dg/warn/Wuninitialized-13.C
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-13.C
@@ -8,12 +8,12 @@
struct shared_count {
shared_count () { }
shared_count (shared_count &r)
- : pi (r.pi) { } // { dg-warning "\\\[-Wuninitialized" }
+ : pi (r.pi) { }
int pi;
};
// There's another (redundant) -Wuninitialized on the line below.
-struct shared_ptr {
+struct shared_ptr { // { dg-warning "\\\[-Wuninitialized" }
int ptr;
shared_count refcount;
};
diff --git a/gcc/testsuite/gnat.dg/use_type1.adb b/gcc/testsuite/gnat.dg/use_type1.adb
new file mode 100644
index 0000000..a324610
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/use_type1.adb
@@ -0,0 +1,16 @@
+-- { dg-do compile }
+
+procedure Use_Type1 is
+
+ package Nested is
+ type T is (X, Y, Z);
+ procedure Proc (Obj : T) is null;
+ end Nested;
+
+ use all type Nested.T;
+
+ Obj : Nested.T := X;
+
+begin
+ Proc (Obj);
+end;
diff --git a/gcc/testsuite/gnat.dg/use_type2.adb b/gcc/testsuite/gnat.dg/use_type2.adb
new file mode 100644
index 0000000..8299636
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/use_type2.adb
@@ -0,0 +1,15 @@
+-- { dg-do compile }
+
+with Ada.Containers.Vectors;
+
+procedure Use_Type2 is
+
+ package Vectors is new Ada.Containers.Vectors (Positive, Character);
+
+ use all type Vectors.Vector;
+
+ X : Vectors.Vector := To_Vector (0);
+
+begin
+ Append (X, 'A');
+end;
diff --git a/gcc/tree-ssa-uninit.cc b/gcc/tree-ssa-uninit.cc
index cb82001..45e789c 100644
--- a/gcc/tree-ssa-uninit.cc
+++ b/gcc/tree-ssa-uninit.cc
@@ -641,6 +641,7 @@ maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs,
return NULL_TREE;
bool found_alloc = false;
+ bool found_clobber_deref_this = false;
if (fentry_reached)
{
@@ -662,12 +663,30 @@ maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs,
tree fndecl = gimple_call_fndecl (def_stmt);
const built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
if (fncode == BUILT_IN_ALLOCA
- || fncode == BUILT_IN_ALLOCA_WITH_ALIGN
- || fncode == BUILT_IN_MALLOC)
+ || fncode == BUILT_IN_ALLOCA_WITH_ALIGN
+ || fncode == BUILT_IN_MALLOC)
found_alloc = true;
break;
}
+ /* The C++ FE for -flifetime-dse=2 marks this parameters
+ of certain constructors with "clobber *this" attribute.
+ Emit uninitialized warnings if we read from what this points
+ to. This is similar to access (write_only, 1) attribute,
+ except it is a -Wuninitialized warning rather than
+ -Wmaybe-uninitialized and doesn't talk about access
+ attribute. */
+ if (SSA_NAME_IS_DEFAULT_DEF (base)
+ && POINTER_TYPE_P (TREE_TYPE (base))
+ && SSA_NAME_VAR (base)
+ && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL
+ && lookup_attribute ("clobber *this",
+ DECL_ATTRIBUTES (SSA_NAME_VAR (base))))
+ {
+ found_clobber_deref_this = true;
+ break;
+ }
+
if (!is_gimple_assign (def_stmt))
break;
@@ -702,7 +721,7 @@ maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs,
/* Do not warn if it can be initialized outside this function.
If we did not reach function entry then we found killing
clobbers on all paths to entry. */
- if (!found_alloc && fentry_reached)
+ if ((!found_alloc && !found_clobber_deref_this) && fentry_reached)
{
if (TREE_CODE (base) == SSA_NAME)
{
diff --git a/gcc/tree.h b/gcc/tree.h
index 6e46374..4a4b8ef 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -900,6 +900,19 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
#define UNUSED_LABEL_P(NODE) \
(LABEL_DECL_CHECK (NODE)->base.default_def_flag)
+/* Label used to goto around artificial .DEFERRED_INIT code for
+ C++ -ftrivial-auto-var-init= purposes with a goto around it.
+ VACUOUS_INIT_LABEL_P flag is used on the lab LABEL_DECL in:
+ goto lab;
+ lab1:
+ v1 = .DEFERRED_INIT (...);
+ v2 = .DEFERRED_INIT (...);
+ lab2:
+ v3 = .DEFERRED_INIT (...);
+ lab: */
+#define VACUOUS_INIT_LABEL_P(NODE) \
+ (LABEL_DECL_CHECK (NODE)->base.nothrow_flag)
+
/* Nonzero means this expression is volatile in the C sense:
its address should be of type `volatile WHATEVER *'.
In other words, the declared item is volatile qualified.