Message ID | ZoVijSB8BjnAIV+2@tucnak |
---|---|
State | New |
Headers | show |
Series | c++: Implement C++26 CWG2819 - Allow cv void * null pointer value conversion to object types in constant expressions | expand |
On 7/3/24 10:39 AM, Jakub Jelinek wrote: > Hi! > > The following patch implements CWG2819 (which wasn't a DR because > it changes behavior of C++26 only). > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2024-07-03 Jakub Jelinek <jakub@redhat.com> > > * constexpr.cc (cxx_eval_constant_expression): CWG2819 - Allow > cv void * null pointer value conversion to object types in constant > expressions. > > * g++.dg/cpp26/constexpr-voidptr3.C: New test. > * g++.dg/cpp0x/constexpr-cast2.C: Adjust expected diagnostics for > C++26. > * g++.dg/cpp0x/constexpr-cast4.C: Likewise. > > --- gcc/cp/constexpr.cc.jj 2024-07-02 22:09:52.493176541 +0200 > +++ gcc/cp/constexpr.cc 2024-07-03 12:46:57.255025849 +0200 > @@ -8157,10 +8157,13 @@ cxx_eval_constant_expression (const cons > || DECL_NAME (decl) == heap_vec_uninit_identifier)) > /* OK */; > /* P2738 (C++26): a conversion from a prvalue P of type "pointer to > - cv void" to a pointer-to-object type T unless P points to an > - object whose type is similar to T. */ > + cv void" to a pointer-to-object type T unless P is a null > + pointer value or points to an object whose type is similar to > + T. */ > else if (cxx_dialect > cxx23) > { > + if (integer_zerop (sop)) > + return build_int_cst (type, 0); This patch should also remove the integer_zerop diagnostic lower in the function, which becomes dead code with this change. > r = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), sop); > if (r) > { > --- gcc/testsuite/g++.dg/cpp26/constexpr-voidptr3.C.jj 2024-07-03 12:35:56.301762995 +0200 > +++ gcc/testsuite/g++.dg/cpp26/constexpr-voidptr3.C 2024-07-03 12:35:51.577825446 +0200 > @@ -0,0 +1,13 @@ > +// CWG 2819 - Cast from null pointer value in a constant expression > +// { dg-do compile { target c++26 } } > + > +struct S { int s; }; > + > +constexpr S * > +foo () > +{ > + void *p = nullptr; > + return static_cast<S *> (p); > +} > + > +static_assert (foo () == nullptr); > --- gcc/testsuite/g++.dg/cpp0x/constexpr-cast2.C.jj 2023-07-17 09:07:42.104283529 +0200 > +++ gcc/testsuite/g++.dg/cpp0x/constexpr-cast2.C 2024-07-03 16:22:33.294916937 +0200 > @@ -5,9 +5,9 @@ > static int i; > constexpr void *vp0 = nullptr; > constexpr void *vpi = &i; > -constexpr int *p1 = (int *) vp0; // { dg-error "cast from .void\\*. is not allowed" } > +constexpr int *p1 = (int *) vp0; // { dg-error "cast from .void\\*. is not allowed" "" { target c++23_down } } > constexpr int *p2 = (int *) vpi; // { dg-error "cast from .void\\*. is not allowed" "" { target c++23_down } } > -constexpr int *p3 = static_cast<int *>(vp0); // { dg-error "cast from .void\\*. is not allowed" } > +constexpr int *p3 = static_cast<int *>(vp0); // { dg-error "cast from .void\\*. is not allowed" "" { target c++23_down } } > constexpr int *p4 = static_cast<int *>(vpi); // { dg-error "cast from .void\\*. is not allowed" "" { target c++23_down } } > constexpr void *p5 = vp0; > constexpr void *p6 = vpi; > --- gcc/testsuite/g++.dg/cpp0x/constexpr-cast4.C.jj 2023-11-02 07:39:18.679201173 +0100 > +++ gcc/testsuite/g++.dg/cpp0x/constexpr-cast4.C 2024-07-03 16:23:29.424197809 +0200 > @@ -8,4 +8,3 @@ constexpr float* pf = static_cast<float* > > constexpr void* vnp = nullptr; > constexpr int* pi2 = static_cast<int*>(vnp); // { dg-error "cast from .void\\*. is not allowed" "" { target c++23_down } } > -// { dg-error "cast from .void\\*. is not allowed in a constant expression because .vnp. does not point to an object" "" { target c++26 } .-1 } > > Jakub >
--- gcc/cp/constexpr.cc.jj 2024-07-02 22:09:52.493176541 +0200 +++ gcc/cp/constexpr.cc 2024-07-03 12:46:57.255025849 +0200 @@ -8157,10 +8157,13 @@ cxx_eval_constant_expression (const cons || DECL_NAME (decl) == heap_vec_uninit_identifier)) /* OK */; /* P2738 (C++26): a conversion from a prvalue P of type "pointer to - cv void" to a pointer-to-object type T unless P points to an - object whose type is similar to T. */ + cv void" to a pointer-to-object type T unless P is a null + pointer value or points to an object whose type is similar to + T. */ else if (cxx_dialect > cxx23) { + if (integer_zerop (sop)) + return build_int_cst (type, 0); r = cxx_fold_indirect_ref (ctx, loc, TREE_TYPE (type), sop); if (r) { --- gcc/testsuite/g++.dg/cpp26/constexpr-voidptr3.C.jj 2024-07-03 12:35:56.301762995 +0200 +++ gcc/testsuite/g++.dg/cpp26/constexpr-voidptr3.C 2024-07-03 12:35:51.577825446 +0200 @@ -0,0 +1,13 @@ +// CWG 2819 - Cast from null pointer value in a constant expression +// { dg-do compile { target c++26 } } + +struct S { int s; }; + +constexpr S * +foo () +{ + void *p = nullptr; + return static_cast<S *> (p); +} + +static_assert (foo () == nullptr); --- gcc/testsuite/g++.dg/cpp0x/constexpr-cast2.C.jj 2023-07-17 09:07:42.104283529 +0200 +++ gcc/testsuite/g++.dg/cpp0x/constexpr-cast2.C 2024-07-03 16:22:33.294916937 +0200 @@ -5,9 +5,9 @@ static int i; constexpr void *vp0 = nullptr; constexpr void *vpi = &i; -constexpr int *p1 = (int *) vp0; // { dg-error "cast from .void\\*. is not allowed" } +constexpr int *p1 = (int *) vp0; // { dg-error "cast from .void\\*. is not allowed" "" { target c++23_down } } constexpr int *p2 = (int *) vpi; // { dg-error "cast from .void\\*. is not allowed" "" { target c++23_down } } -constexpr int *p3 = static_cast<int *>(vp0); // { dg-error "cast from .void\\*. is not allowed" } +constexpr int *p3 = static_cast<int *>(vp0); // { dg-error "cast from .void\\*. is not allowed" "" { target c++23_down } } constexpr int *p4 = static_cast<int *>(vpi); // { dg-error "cast from .void\\*. is not allowed" "" { target c++23_down } } constexpr void *p5 = vp0; constexpr void *p6 = vpi; --- gcc/testsuite/g++.dg/cpp0x/constexpr-cast4.C.jj 2023-11-02 07:39:18.679201173 +0100 +++ gcc/testsuite/g++.dg/cpp0x/constexpr-cast4.C 2024-07-03 16:23:29.424197809 +0200 @@ -8,4 +8,3 @@ constexpr float* pf = static_cast<float* constexpr void* vnp = nullptr; constexpr int* pi2 = static_cast<int*>(vnp); // { dg-error "cast from .void\\*. is not allowed" "" { target c++23_down } } -// { dg-error "cast from .void\\*. is not allowed in a constant expression because .vnp. does not point to an object" "" { target c++26 } .-1 }