Repository navigation
Default member initializer's implicit this binds to a nested aggregate temporary of the same class #324
Momen-G-Ar
started this conversation in
Issue Triage - Compilation
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Issue Summary
When the default member initializer of class
Ycontains an aggregate initialization of anotherY, an implicitthis->minside that default member initializer refers to the innerYtemporary rather than theYobject being initialized. The generated code therefore reads the wrong object.In
unsigned n = Y{2, k}.n;, thekis(*this).k([class.mfct.non-static]/3 in C++17/C++20, [expr.prim.id.general]/2 in the current draft), and in aggregate initializationthisis the aggregate whose element is initialized from the default member initializer ([dcl.init.aggr]/5.1, and the C++17 exampleint d = b[a]in [dcl.init.aggr]/8). Sonew Y{1}must given == 1. EDG givesn == 2, the inner temporary'sk. The program is well-formed:Y{2, k}initializesnexplicitly, so it does not usen's default member initializer ([dcl.init.aggr]/12 in C++20).This reproduces in EDG 6.5, 6.7, 6.8, 6.9, 7.0 and
main, in every mode from--c++17to--c++26, both in strict mode and with GNU emulation. g++ 15.3 and clang++ 21.1 given == 1.Reproducing Source Code
The program should exit with status 0. With EDG it aborts.
Command-line Options
eccp --c++20 reduced.cpp && ./a.out
Type of Issue
[Back End] There is a problem with the generated C code.
Additional Details
Actual vs expected:
It was originally found with this variant, where
y.nis 2 instead of 1:The lowered C (
-k) for that variant shows the wrong object.__T1is theY{2, k}temporary:{ __T1.k = 2U; __T1.n = 0U; } (__6042_5_y.n) = ((__T4 = ((__T2 = (((__T1.n) = (__T1.k)), __T1)), ((__T3 = __T2), __T3)), __T4.n));__T1.n = __T1.kshould be__T1.n = __6042_5_y.k.These were checked with
main:new Y{1}, or fromreturn Y{1};in a function. Also wrong: the innerY{2, k}is passed to a function, by value or byconst Y&.Y y{1};andY a = Y{1};withn = Y{2, k}.n;; writingthis->kexplicitly; a nested aggregate of a different class (Z{2, k});Ywith constructors (not an aggregate).The cause may be
lower_param_refinsrc/lower_il.c. While lowering a dynamic aggregate constant, it replaces thethisof a default member initializer by searchingaggregate_this_stackfrom the innermost entry outward, and it takes the first entry whose type matches. A comment there says "there can only be one". The innerY{2, k}(pushed inlower_dynamic_init_aggregate_constant,src/lower_init.c) is a secondYentry on top of the outer one, sothisbinds to the inner temporary.Front end configuration (
--dump_configuration, linux-gcc-debug at 4e739c2): nsdmi_self_aggr_init-config.txtReproducing (Standard) Configuration(s)
linux-gcc-debug
Reproducing (Non-standard) Configuration
No response
I acknowledge that:
LICENSE.txtfile in my.zipor.tar.gzupload. If I included aLICENSE.txtfile, any tests created using the reproducing source code will be governed by the terms of the license I provided instead.All reactions