On Tue, Sep 02, 2025 at 09:35:04PM +0000, Qing Zhao wrote: > > I think I've mentioned it earlier, but -ftrivial-auto-var-init= doesn't > > work at all for C++. > You mean that -ftrivial-auto-var-init hasn’t work at all for C++’s auto > variables with non-trivial ctors?
Yeah. Actually, it probably also works if non-trivial ctors are constexpr and the ctors are actually optimized into TREE_CONSTANT DECL_INITIALIZER. > > With C++26 P2795R5 being voted in, if we were to default to say > > -ftrivial-auto-var-init=zero for -std=c++26/-std=gnu++26, that would mean > > the paper isn't really implemented. > > I briefly read C++26 P2795R5 this morning (still have some questions, not > fully understand yet), my major question is: > > When -ftrivial-auto-var-init=zero is combined with C++26 P2795R5, what’s the > correct behavior the user is expecting? When reading an uninitialized > variable > is considered an well-defined erroneous behavior, can the user still use > -ftrivial-auto-var-init to initialize the auto vairables? I think it is pretty much the same thing, we want -Wuninitialized to complain both in -std=c++26 and if -ftrivial-auto-var-init={zero,pattern} and still want to initialize (and either zero or pattern initialization is fine). So I'd go for -std={gnu,c}++26 implying flag_auto_var_init = AUTO_INIT_CXX26 if -ftrivial-auto-var-init={zero,pattern} has not been specified, and for that mode most likely just zero initialize and don't bother with padding bits. Plus as Jason said, move the CLOBBER_OBJECT_BEGIN clobbers from ctors for flag_auto_var_init != AUTO_INIT_UNINITIALIZED && flag_lifetime_dse > 1 to before the whole object is initialized in all places where we emit calls to the non-trivial ctors and if it initializes a VAR_DECL (rather than say heap) emit .DEFERRED_INIT calls after those. But there is one thing the paper doesn't care about, which looks like a show stopper to me, in particular the stuff -Wtrivial-auto-var-init warning warns about. Consider: template <typename T> void bar (T &); template <typename T> void foo (int x) { switch (x) { case 1: T t; bar (t); // FALLTHRU case 2: bar (t); break; default: break; } } struct S { S (); S (int); ~S (); int s; }; void baz (int x) { foo <S> (x); foo <int> (x); } The foo <S> instantiation is invalid and we do diagnose that as error that the switch (but could be goto too) jumps across initialization of the t variable. Similarly if there is T t = 42; instead of T t; both foo <S> and foo <int> will be rejected. But with just T t; in there foo <int> is accepted as valid, one can jump across it but it used to be undefined behavior in both bar (t); calls, or say with t = 42; before the first bar just undefined behavior in case of foo <int> (2); But now it is supposed to be erroneous behavior but it is unclear where it can initialize the t variable to the erroneous value. Silently promote the variable to wider scope and initialize there, or add some wider scope flag which tracks if it is initialized or not and on any label initializes it if not yet initialized? It is unclear how such wider scope vars would play with say OpenMP/OpenACC. See http://eel.is/c++draft/stmt.dcl#2 and http://eel.is/c++draft/basic.life#2.sentence-2 > > One problem with this are [[indeterminate]] vars, if .DEFERRED_INIT is > > emitted in the ctors, the vars will be cleared even if they are > > [[indeterminate]] (unless the ctors are inlined and some optimization > > figures out, these vars are [[indeterminate]], let's drop all .DEFERRED_INIT > > calls for those and their subparts. > > If the value need to be kept as [[indeterminate]], what’s the purpose to use > -ftrivial-auto-var-init? I think even explicit -ftrivial-auto-var-init={zero,pattern} should treat [[indeterminate]] variables like those having the [[gnu::uninitialized]] attribute. Jakub