aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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/config/riscv/predicates.md7
-rw-r--r--gcc/config/riscv/riscv-protos.h1
-rw-r--r--gcc/config/riscv/riscv-v.cc12
-rw-r--r--gcc/config/riscv/riscv-vsetvl.cc5
-rw-r--r--gcc/config/riscv/riscv.cc26
-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.cc2
-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/fortran/trans-io.cc4
-rw-r--r--gcc/gimplify.cc173
-rw-r--r--gcc/ipa-split.cc9
-rw-r--r--gcc/match.pd28
-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/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/gcc.dg/int-bwise-opt-1.c31
-rw-r--r--gcc/testsuite/gcc.dg/int-bwise-opt-2.c15
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr122153-1.c30
-rw-r--r--gcc/testsuite/gcc.target/i386/pr122104.c12
-rw-r--r--gcc/testsuite/gcc.target/riscv/pr122114.c22
-rw-r--r--gcc/testsuite/gcc.target/riscv/pr122147.c14
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/pr118945-1.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/pr118945-2.c28
-rw-r--r--gcc/testsuite/gfortran.dg/implied_do_io_9.f9072
-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-forwprop.cc9
-rw-r--r--gcc/tree-ssa-math-opts.cc1
-rw-r--r--gcc/tree-ssa-phiopt.cc44
-rw-r--r--gcc/tree-ssa-uninit.cc25
-rw-r--r--gcc/tree.h13
78 files changed, 2419 insertions, 208 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/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index 056f9e2..f811a4e 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -334,6 +334,13 @@
&& riscv_split_symbol_type (symbol_type)
&& symbol_type != SYMBOL_PCREL;
+ /* Be tight about the SUBREGs we accept. In particular,
+ (subreg (mem)) has been discouraged for decades. Just
+ allow (subreg (reg)) until such time as we see a strong
+ need to be more permissive. */
+ case SUBREG:
+ return REG_P (SUBREG_REG (op));
+
default:
return true;
}
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index e4473f4..346d7a8 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -832,6 +832,7 @@ extern bool th_print_operand_address (FILE *, machine_mode, rtx);
#endif
extern bool strided_load_broadcast_p (void);
+extern bool riscv_prefer_agnostic_p (void);
extern bool riscv_use_divmod_expander (void);
void riscv_init_cumulative_args (CUMULATIVE_ARGS *, const_tree, rtx, tree, int);
extern bool
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index 8021bc1..1d7d8a6 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -2140,10 +2140,8 @@ get_ma (rtx ma)
enum tail_policy
get_prefer_tail_policy ()
{
- /* TODO: By default, we choose to use TAIL_ANY which allows
- compiler pick up either agnostic or undisturbed. Maybe we
- will have a compile option like -mprefer=agnostic to set
- this value???. */
+ if (riscv_prefer_agnostic_p ())
+ return TAIL_AGNOSTIC;
return TAIL_ANY;
}
@@ -2151,10 +2149,8 @@ get_prefer_tail_policy ()
enum mask_policy
get_prefer_mask_policy ()
{
- /* TODO: By default, we choose to use MASK_ANY which allows
- compiler pick up either agnostic or undisturbed. Maybe we
- will have a compile option like -mprefer=agnostic to set
- this value???. */
+ if (riscv_prefer_agnostic_p ())
+ return MASK_AGNOSTIC;
return MASK_ANY;
}
diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc
index 4fe0ae6..3586d0c 100644
--- a/gcc/config/riscv/riscv-vsetvl.cc
+++ b/gcc/config/riscv/riscv-vsetvl.cc
@@ -1144,9 +1144,10 @@ public:
dflags |= demand_flags::DEMAND_LMUL_P;
}
- if (!m_ta)
+ /* Demand policy for agnostic if the uarch has a preference. */
+ if (!m_ta || riscv_prefer_agnostic_p ())
dflags |= demand_flags::DEMAND_TAIL_POLICY_P;
- if (!m_ma)
+ if (!m_ma || riscv_prefer_agnostic_p ())
dflags |= demand_flags::DEMAND_MASK_POLICY_P;
}
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 41ee401..c81a2e4 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -317,6 +317,7 @@ struct riscv_tune_param
const char *function_align;
const char *jump_align;
const char *loop_align;
+ bool prefer_agnostic;
};
@@ -481,6 +482,7 @@ static const struct riscv_tune_param generic_tune_info = {
NULL, /* function_align */
NULL, /* jump_align */
NULL, /* loop_align */
+ false, /* prefer-agnostic. */
};
/* Costs to use when optimizing for rocket. */
@@ -505,6 +507,7 @@ static const struct riscv_tune_param rocket_tune_info = {
NULL, /* function_align */
NULL, /* jump_align */
NULL, /* loop_align */
+ false, /* prefer-agnostic. */
};
/* Costs to use when optimizing for Sifive 7 Series. */
@@ -529,6 +532,7 @@ static const struct riscv_tune_param sifive_7_tune_info = {
NULL, /* function_align */
NULL, /* jump_align */
NULL, /* loop_align */
+ false, /* prefer-agnostic. */
};
/* Costs to use when optimizing for Sifive p400 Series. */
@@ -553,6 +557,7 @@ static const struct riscv_tune_param sifive_p400_tune_info = {
NULL, /* function_align */
NULL, /* jump_align */
NULL, /* loop_align */
+ true, /* prefer-agnostic. */
};
/* Costs to use when optimizing for Sifive p600 Series. */
@@ -577,6 +582,7 @@ static const struct riscv_tune_param sifive_p600_tune_info = {
NULL, /* function_align */
NULL, /* jump_align */
NULL, /* loop_align */
+ true, /* prefer-agnostic. */
};
/* Costs to use when optimizing for T-HEAD c906. */
@@ -601,6 +607,7 @@ static const struct riscv_tune_param thead_c906_tune_info = {
NULL, /* function_align */
NULL, /* jump_align */
NULL, /* loop_align */
+ false, /* prefer-agnostic. */
};
/* Costs to use when optimizing for xiangshan nanhu. */
@@ -625,6 +632,7 @@ static const struct riscv_tune_param xiangshan_nanhu_tune_info = {
NULL, /* function_align */
NULL, /* jump_align */
NULL, /* loop_align */
+ true, /* prefer-agnostic. */
};
/* Costs to use when optimizing for a generic ooo profile. */
@@ -649,6 +657,7 @@ static const struct riscv_tune_param generic_ooo_tune_info = {
NULL, /* function_align */
NULL, /* jump_align */
NULL, /* loop_align */
+ true, /* prefer-agnostic. */
};
/* Costs to use when optimizing for Tenstorrent Ascalon 8 wide. */
@@ -673,6 +682,7 @@ static const struct riscv_tune_param tt_ascalon_d8_tune_info = {
NULL, /* function_align */
NULL, /* jump_align */
NULL, /* loop_align */
+ true, /* prefer-agnostic. */
};
/* Costs to use when optimizing for size. */
@@ -697,6 +707,7 @@ static const struct riscv_tune_param optimize_size_tune_info = {
NULL, /* function_align */
NULL, /* jump_align */
NULL, /* loop_align */
+ false, /* prefer-agnostic. */
};
/* Costs to use when optimizing for MIPS P8700 */
@@ -720,7 +731,8 @@ static const struct riscv_tune_param mips_p8700_tune_info = {
NULL, /* vector cost */
NULL, /* function_align */
NULL, /* jump_align */
- NULL, /* loop_align */
+ NULL, /* loop_align. */
+ true, /* prefer-agnostic. */
};
static bool riscv_avoid_shrink_wrapping_separate ();
@@ -9027,8 +9039,7 @@ riscv_allocate_and_probe_stack_space (rtx temp1, HOST_WIDE_INT size)
from the top of the frame, as it might be lowered before.
To consider the correct SP addresses for the CFA notes, it is needed
to correct them with the initial offset value. */
- HOST_WIDE_INT initial_cfa_offset
- = cfun->machine->frame.total_size.to_constant () - size;
+ poly_int64 initial_cfa_offset = cfun->machine->frame.total_size - size;
if (!frame_pointer_needed)
{
@@ -12842,6 +12853,15 @@ strided_load_broadcast_p ()
return tune_param->use_zero_stride_load;
}
+/* Return TRUE if we should use the tail agnostic and mask agnostic policies for
+ vector code, false otherwise. */
+
+bool
+riscv_prefer_agnostic_p ()
+{
+ return tune_param->prefer_agnostic;
+}
+
/* Return TRUE if we should use the divmod expander, FALSE otherwise. This
allows the behavior to be tuned for specific implementations as well as
when optimizing for size. */
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 0403148..362cddb 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -31186,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/fortran/trans-io.cc b/gcc/fortran/trans-io.cc
index df2fef7..9360bdd 100644
--- a/gcc/fortran/trans-io.cc
+++ b/gcc/fortran/trans-io.cc
@@ -2646,7 +2646,9 @@ gfc_trans_transfer (gfc_code * code)
&& ((expr->symtree->n.sym->ts.type == BT_DERIVED && expr->ts.deferred)
|| (expr->symtree->n.sym->assoc
&& expr->symtree->n.sym->assoc->variable)
- || gfc_expr_attr (expr).pointer))
+ || gfc_expr_attr (expr).pointer
+ || (expr->symtree->n.sym->attr.pointer
+ && gfc_expr_attr (expr).target)))
goto scalarize;
/* With array-bounds checking enabled, force scalarization in some
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/match.pd b/gcc/match.pd
index b3fd26e..6f896aa 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -6808,6 +6808,34 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
@2))
)
+#if GIMPLE
+/* Given two integers a and b:
+ (a != b) & ((a|b) != 0) -> (a != b)
+ (a != b) | ((a|b) != 0) -> ((a|b) != 0)
+ (a == b) & ((a|b) == 0) -> ((a|b) == 0)
+ (a == b) | ((a|b) == 0) -> (a == b)
+ (a != b) & ((a|b) == 0) -> false
+ (a == b) | ((a|b) != 0) -> true */
+(simplify
+ (bit_and:c (ne:c @0 @1) (ne (bit_ior @0 @1) integer_zerop))
+ (ne @0 @1))
+(simplify
+ (bit_ior:c (ne:c @0 @1) (ne (bit_ior @0 @1) integer_zerop))
+ (ne (bit_ior @0 @1) { integer_zero_node; }))
+(simplify
+ (bit_and:c (eq:c @0 @1) (eq (bit_ior @0 @1) integer_zerop))
+ (eq (bit_ior @0 @1) { integer_zero_node; }))
+(simplify
+ (bit_ior:c (eq:c @0 @1) (eq (bit_ior @0 @1) integer_zerop))
+ (eq @0 @1))
+(simplify
+ (bit_and:c (ne:c @0 @1) (eq (bit_ior @0 @1) integer_zerop))
+ { build_zero_cst (type); })
+(simplify
+ (bit_ior:c (eq:c @0 @1) (ne (bit_ior @0 @1) integer_zerop))
+ { build_one_cst (type); })
+#endif
+
/* These was part of minmax phiopt. */
/* Optimize (a CMP b) ? minmax<a, c> : minmax<b, c>
to minmax<min/max<a, b>, c> */
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/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/gcc.dg/int-bwise-opt-1.c b/gcc/testsuite/gcc.dg/int-bwise-opt-1.c
new file mode 100644
index 0000000..11ea9ac
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/int-bwise-opt-1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int f1(int a, int b)
+{
+ return (a != b) & ((a | b) != 0);
+}
+
+int f2(int a, int b)
+{
+ return (a == b) | ((a | b) == 0);
+}
+
+int f3(int a, int b)
+{
+ return (a != b) & ((a | b) == 0);
+}
+
+int f4(int a, int b)
+{
+ return (a == b) | ((a | b) != 0);
+}
+
+/* { dg-final { scan-tree-dump-times "\\\|" 0 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "\&" 0 "optimized" } } */
+
+/* f3 should fold to `1` (true). */
+/* { dg-final { scan-tree-dump-times "return 1;" 1 "optimized" } } */
+
+/* f4 should fold to `0` (false). */
+/* { dg-final { scan-tree-dump-times "return 0;" 1 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/int-bwise-opt-2.c b/gcc/testsuite/gcc.dg/int-bwise-opt-2.c
new file mode 100644
index 0000000..cc1a48b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/int-bwise-opt-2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int f1(int a, int b)
+{
+ return (a != b) | ((a | b) != 0);
+}
+
+int f2(int a, int b)
+{
+ return (a == b) & ((a | b) == 0);
+}
+
+ /* { dg-final { scan-tree-dump-times "a == b" 0 "optimized" } } */
+ /* { dg-final { scan-tree-dump-times "a != b" 0 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr122153-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr122153-1.c
new file mode 100644
index 0000000..d6e7527
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr122153-1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-phiopt1" } */
+/* PR tree-optimization/122153 */
+struct s1
+{
+ int t;
+};
+void g(struct s1*);
+struct s1 f(int *a, int c, int d)
+{
+ struct s1 r;
+ int t1;
+ if (c < d)
+ {
+ r = (struct s1){};
+ t1 = c;
+ }
+ else
+ {
+ r = (struct s1){};
+ t1 = d;
+ }
+ g(&r);
+ r.t = t1;
+ return r;
+}
+/* the `r = {};` store should be commonialized out of the conditional
+ and produce a MIN_EXPR in phiopt1. */
+
+/* { dg-final { scan-tree-dump "MIN_EXPR" "phiopt1" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr122104.c b/gcc/testsuite/gcc.target/i386/pr122104.c
new file mode 100644
index 0000000..be88933
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr122104.c
@@ -0,0 +1,12 @@
+/* PR tree-optimization/122104 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-alias" } */
+/* { dg-final { scan-tree-dump "\\.MUL_OVERFLOW" "widening_mul" } } */
+/* { dg-final { scan-tree-dump-not "# RANGE \\\[irange\\\] unsigned int \\\[1, " "widening_mul" } } */
+
+int
+foo (int x)
+{
+ int r = (unsigned) x * 35;
+ return x && ((unsigned) r / x) != 35U;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/pr122114.c b/gcc/testsuite/gcc.target/riscv/pr122114.c
new file mode 100644
index 0000000..ccb2ec9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr122114.c
@@ -0,0 +1,22 @@
+/* { dg-do compile { target { rv64 } } } */
+/* { dg-options "-O2 -fstack-clash-protection -march=rv64gcv_zvl256b -mabi=lp64d" } */
+
+int pk_gen_i, pk_gen_j;
+long pk_gen_buf[4];
+long pk_gen_t;
+
+void vec_mul(long *, long *, long *);
+void uint64_is_zero_declassify(long);
+
+void pk_gen() {
+ long consts[128][13], prod[128][13];
+
+ vec_mul(prod[pk_gen_j], prod[pk_gen_j], consts[pk_gen_j]);
+
+ for (; pk_gen_i;) {
+ for (; pk_gen_j; pk_gen_j++)
+ pk_gen_t |= pk_gen_buf[pk_gen_j];
+
+ uint64_is_zero_declassify(pk_gen_t);
+ }
+}
diff --git a/gcc/testsuite/gcc.target/riscv/pr122147.c b/gcc/testsuite/gcc.target/riscv/pr122147.c
new file mode 100644
index 0000000..14da321
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr122147.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-w -march=rv64gcv -mabi=lp64d" { target rv64 } } */
+/* { dg-additional-options "-w -march=rv32gcv -mabi=ilp32" { target rv32 } } */
+
+typedef __attribute__((__vector_size__ (4))) _Float16 F;
+_Complex char cc;
+F f;
+
+void
+foo ()
+{
+ __builtin_memmove (&f, &cc, 2);
+ f *= f;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr118945-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr118945-1.c
new file mode 100644
index 0000000..fc37bef
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr118945-1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-mtune=generic-ooo -O3 -march=rv64gcv_zvl256b_zba -mabi=lp64d -mrvv-max-lmul=m2 -mrvv-vector-bits=scalable" } */
+
+int test(int* in, int n)
+{
+ int accum = 0;
+ for (int i = 0; i < n; i++)
+ accum += in[i];
+
+ return accum;
+}
+
+/* { dg-final { scan-assembler-times {vsetvli\s+[a-z0-9]+,\s*[a-z0-9]+,\s*e[0-9]+,\s*m[f0-9]+,\s*ta,\s*ma} 3 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+[a-z0-9]+,\s*[a-z0-9]+,\s*e[0-9]+,\s*m[f0-9]+,\s*tu,\s*ma} 1 } } */
+
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr118945-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr118945-2.c
new file mode 100644
index 0000000..9565740
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr118945-2.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rva23u64 -mtune=generic-ooo -Ofast -S" } */
+
+void vmult(
+ double* dst,
+ const double* src,
+ const unsigned int* rowstart,
+ const unsigned int* colnums,
+ const double* val,
+ const unsigned int n_rows
+) {
+ const double* val_ptr = &val[rowstart[0]];
+ const unsigned int* colnum_ptr = &colnums[rowstart[0]];
+ double* dst_ptr = dst;
+
+ for (unsigned int row = 0; row < n_rows; ++row) {
+ double s = 0.;
+ const double* const val_end_of_row = &val[rowstart[row + 1]];
+ while (val_ptr != val_end_of_row) {
+ s += *val_ptr++ * src[*colnum_ptr++];
+ }
+ *dst_ptr++ = s;
+ }
+}
+
+/* { dg-final { scan-assembler-times {vsetvli\s+[a-z0-9]+,\s*[a-z0-9]+,\s*e[0-9]+,\s*m[f0-9]+,\s*ta,\s*ma} 4 } } */
+/* { dg-final { scan-assembler-times {vsetvli\s+[a-z0-9]+,\s*[a-z0-9]+,\s*e[0-9]+,\s*m[f0-9]+,\s*tu,\s*ma} 1 } } */
+
diff --git a/gcc/testsuite/gfortran.dg/implied_do_io_9.f90 b/gcc/testsuite/gfortran.dg/implied_do_io_9.f90
new file mode 100644
index 0000000..5180b8a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/implied_do_io_9.f90
@@ -0,0 +1,72 @@
+! { dg-do run }
+! { dg-additional-options "-O2" }
+!
+! PR fortran/107968
+!
+! Verify that array I/O optimization is not used for a section
+! of an array pointer as the pointee can be non-contiguous
+!
+! Contributed by Nils Dreier
+
+PROGRAM foo
+ implicit none
+
+ TYPE t_geographical_coordinates
+ REAL :: lon
+ REAL :: lat
+ END TYPE t_geographical_coordinates
+
+ TYPE t_vertices
+ REAL, POINTER :: vlon(:) => null()
+ REAL, POINTER :: vlat(:) => null()
+ END TYPE t_vertices
+
+ TYPE(t_geographical_coordinates), TARGET :: vertex(2)
+ TYPE(t_vertices), POINTER :: vertices_pointer
+ TYPE(t_vertices), TARGET :: vertices_target
+
+ character(24) :: s0, s1, s2
+ character(*), parameter :: fmt = '(2f8.3)'
+
+ ! initialization
+ vertex%lon = [1,3]
+ vertex%lat = [2,4]
+
+ ! obtain pointer to (non-contiguous) field
+ vertices_target%vlon => vertex%lon
+
+ ! reference output of write
+ write (s0,fmt) vertex%lon
+
+ ! set pointer vertices_pointer in a subroutine
+ CALL set_vertices_pointer(vertices_target)
+
+ write (s1,fmt) vertices_pointer%vlon
+ write (s2,fmt) vertices_pointer%vlon(1:)
+ if (s1 /= s0 .or. s2 /= s0) then
+ print *, s0, s1, s2
+ stop 3
+ end if
+
+CONTAINS
+
+ SUBROUTINE set_vertices_pointer(vertices)
+ TYPE(t_vertices), POINTER, INTENT(IN) :: vertices
+
+ vertices_pointer => vertices
+
+ write (s1,fmt) vertices %vlon
+ write (s2,fmt) vertices %vlon(1:)
+ if (s1 /= s0 .or. s2 /= s0) then
+ print *, s0, s1, s2
+ stop 1
+ end if
+
+ write (s1,fmt) vertices_pointer%vlon
+ write (s2,fmt) vertices_pointer%vlon(1:)
+ if (s1 /= s0 .or. s2 /= s0) then
+ print *, s0, s1, s2
+ stop 2
+ end if
+ END SUBROUTINE set_vertices_pointer
+END PROGRAM foo
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-forwprop.cc b/gcc/tree-ssa-forwprop.cc
index 2c6e1ea..ad09f73 100644
--- a/gcc/tree-ssa-forwprop.cc
+++ b/gcc/tree-ssa-forwprop.cc
@@ -5451,7 +5451,8 @@ pass_forwprop::execute (function *fun)
do
{
gimple *orig_stmt = stmt = gsi_stmt (gsi);
- bool was_noreturn = (is_gimple_call (stmt)
+ bool was_call = is_gimple_call (stmt);
+ bool was_noreturn = (was_call
&& gimple_call_noreturn_p (stmt));
changed = false;
@@ -5465,8 +5466,10 @@ pass_forwprop::execute (function *fun)
changed = true;
/* There is no updating of the address
taken after the last forwprop so update
- the addresses when a folding happened. */
- if (last_p)
+ the addresses when a folding happened to a call.
+ The va_* builtins can remove taking of the address so
+ can the sincos->cexpi transformation. See PR 39643 and PR 20983. */
+ if (was_call && last_p)
todoflags |= TODO_update_address_taken;
stmt = gsi_stmt (gsi);
/* Cleanup the CFG if we simplified a condition to
diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
index a9903b6..0db39f3 100644
--- a/gcc/tree-ssa-math-opts.cc
+++ b/gcc/tree-ssa-math-opts.cc
@@ -3834,6 +3834,7 @@ maybe_optimize_guarding_check (vec<gimple *> &mul_stmts, gimple *cond_stmt,
else
gimple_cond_make_false (zero_cond);
update_stmt (zero_cond);
+ reset_flow_sensitive_info_in_bb (bb);
*cfg_changed = true;
}
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index e1c9e12..bdd1f73 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -3645,6 +3645,7 @@ cond_if_else_store_replacement_1 (basic_block then_bb, basic_block else_bb,
gimple_stmt_iterator gsi;
gphi *newphi;
gassign *new_stmt;
+ bool empty_constructor = false;
if (then_assign == NULL
|| !gimple_assign_single_p (then_assign)
@@ -3659,8 +3660,7 @@ cond_if_else_store_replacement_1 (basic_block then_bb, basic_block else_bb,
return false;
lhs = gimple_assign_lhs (then_assign);
- if (!is_gimple_reg_type (TREE_TYPE (lhs))
- || !operand_equal_p (lhs, gimple_assign_lhs (else_assign), 0))
+ if (!operand_equal_p (lhs, gimple_assign_lhs (else_assign), 0))
return false;
lhs_base = get_base_address (lhs);
@@ -3673,6 +3673,16 @@ cond_if_else_store_replacement_1 (basic_block then_bb, basic_block else_bb,
then_locus = gimple_location (then_assign);
else_locus = gimple_location (else_assign);
+ if (!is_gimple_reg_type (TREE_TYPE (lhs)))
+ {
+ if (!operand_equal_p (then_rhs, else_rhs))
+ return false;
+ /* Currently only handle commoning of `= {}`. */
+ if (TREE_CODE (then_rhs) != CONSTRUCTOR)
+ return false;
+ empty_constructor = true;
+ }
+
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf(dump_file, "factoring out stores:\n\tthen:\n");
@@ -3699,12 +3709,17 @@ cond_if_else_store_replacement_1 (basic_block then_bb, basic_block else_bb,
/* 2) Create a PHI node at the join block, with one argument
holding the old RHS, and the other holding the temporary
where we stored the old memory contents. */
- name = make_temp_ssa_name (TREE_TYPE (lhs), NULL, "cstore");
- newphi = create_phi_node (name, join_bb);
- add_phi_arg (newphi, then_rhs, EDGE_SUCC (then_bb, 0), then_locus);
- add_phi_arg (newphi, else_rhs, EDGE_SUCC (else_bb, 0), else_locus);
+ if (empty_constructor)
+ name = unshare_expr (then_rhs);
+ else
+ {
+ name = make_temp_ssa_name (TREE_TYPE (lhs), NULL, "cstore");
+ newphi = create_phi_node (name, join_bb);
+ add_phi_arg (newphi, then_rhs, EDGE_SUCC (then_bb, 0), then_locus);
+ add_phi_arg (newphi, else_rhs, EDGE_SUCC (else_bb, 0), else_locus);
+ }
- new_stmt = gimple_build_assign (lhs, gimple_phi_result (newphi));
+ new_stmt = gimple_build_assign (lhs, name);
/* Update the vdef for the new store statement. */
tree newvphilhs = make_ssa_name (gimple_vop (cfun));
tree vdef = gimple_phi_result (vphi);
@@ -3715,16 +3730,21 @@ cond_if_else_store_replacement_1 (basic_block then_bb, basic_block else_bb,
update_stmt (vphi);
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf(dump_file, "to use phi:\n");
- print_gimple_stmt (dump_file, newphi, 0,
- TDF_VOPS|TDF_MEMSYMS);
- fprintf(dump_file, "\n");
+ if (!empty_constructor)
+ {
+ fprintf(dump_file, "to use phi:\n");
+ print_gimple_stmt (dump_file, newphi, 0,
+ TDF_VOPS|TDF_MEMSYMS);
+ fprintf(dump_file, "\n");
+ }
+ else
+ fprintf(dump_file, "to:\n");
print_gimple_stmt (dump_file, new_stmt, 0,
TDF_VOPS|TDF_MEMSYMS);
fprintf(dump_file, "\n\n");
}
- /* 3) Insert that PHI node. */
+ /* 3) Insert that new store. */
gsi = gsi_after_labels (join_bb);
if (gsi_end_p (gsi))
{
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.