babadany2999 wrote: Hi @zwuis, thanks for the review!
I've used the following in my reasoning: [basic.def.odr](https://eel.is/c++draft/basic.def.odr) and [dcl.struct.bind](https://eel.is/c++draft/dcl.struct.bind). According to `[basic.def.odr] p5`: > A variable is named by an expression if the expression is an id-expression or > splice-expression ([[expr.prim.splice]]) that designates it. A variable x that is named by a potentially evaluated expression N that appears at a point P is odr-used by N unless[...] The statement A variable is named by an expression if the expression is an id-expression applies here due to `[dcl.struct.bind] p1`: > First, a variable with a unique name e is introduced. To establish the bindings to the subobjects of `e`, expressions like ```e.m_i```, ```e[i]```, or ```get<i>(e)``` are formed. Because these expressions do not appear in an unevaluated context, they are potentially evaluated expressions naming `e`. Therefore, `e` is odr-used unless one of the exceptions in `p5` applies. Now checking the invariants: `[basic.def.odr] p5.1`: > x is a reference that is usable in constant expressions at P > ([[expr.const.init]]) According to `[dcl.struct.bind] p1`, in a **by-value** structured binding declaration (with no ref-qualifiers), `e` is defined as an object: > If the assignment-expression in the initializer has array type cv1 A and no > ref-qualifier is present, e is defined by attribute-specifier-seqopt S cv A e > ; [...] Otherwise, e is defined as-if by attribute-specifier-seqopt > decl-specifier-seq ref-qualifieropt e initializer ; Because `e` is an object and not a reference, `p5.1` does not apply. `[basic.def.odr] p5.2`: > N is an element of the set of potential results of an expression E, where [(5.2.1)] E is a discarded-value expression ([[expr.context]]) to which the lvalue-to-rvalue conversion is not applied, or [(5.2.2)] x is a non-volatile object that is usable in constant expressions at P and has no mutable subobjects, and [(5.2.2.1)] E is a class member access expression ([[expr.ref]]) naming a non-static data member of reference type and whose object expression has non-volatile-qualified type, or [(5.2.2.2)] the lvalue-to-rvalue conversion ([[conv.lval]]) is applied to E and E has non-volatile-qualified non-class type. According to `[dcl.struct.bind] p3` and `[dcl.struct.bind] p6, p7 and p8`: > (p3) Let SBi denote the ith structured binding in the structured binding > declaration after expanding the structured binding pack, if any. > (p6) [...] Each SBi is the name of an lvalue that refers to the element i of > the array and whose type is T > (p7) [...] Each SBi is the name of an lvalue of type Ti that refers to the > object bound to ri, [...] > (p8) Designating the non-static data members of E as m0, m1, m2,… (in > declaration order), each SBi is the name of an lvalue that refers to the > member mi of e and whose type is that of e.mi ([[expr.ref]]); Because paragraphs `6`, `7`, and `8` explicitly mandate that the expressions mapping `SBi` to `e` establish `lvalues` referring to the subobjects, the result of the expression is not discarded, which disproves `[(5.2.1)]`. Furthermore, because it establishes an `lvalue` alias to retain object identity, it does not undergo an `lvalue-to-rvalue` conversion, which disproves `[(5.2.2.2)]`. Since none of the non-ODR-use exceptions apply, the hidden variable `e` is inherently ODR-used by the standard definition. ### Note This is my first time reading the standard, so **please** point out where my reasoning is incorrect, whenever you have a moment. I also hadn't used the reasoning when applying the fix; I basically just fixed the issue without knowing if that fix was correct according to the standard. As such, I will try to refer to the standard from now on to ensure that my fixes are strictly correct. Thank you for your review! https://github.com/llvm/llvm-project/pull/213534 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
