[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #26 from Stas Sergeev --- (In reply to Jonathan Wakely from comment #23) > What you want (and what everybody I've seen asking for similar things) But comment #17 shows the different use of reinterpret_cast - offsetof in templates. What work-around would you suggest for that case? > A more limited extension that solves the problem is a lot more reasonable. If it would have been done before the feature is removed, and for every possible use-case, then yes. :) In any case, what limited extension would you suggest for the offsetof case? Would something like the below[1] considered as such extension (currently doesn't compile): --- template struct B { static constexpr int off = O(); }; struct A { char a; B<[](){ return offsetof(A, a); }> b; }; --- Below is the very similar code[2] that actually compiles: --- template struct B { static constexpr int off = O(); }; struct A { char a; static constexpr int off(void) { return offsetof(A, a); } B b; }; --- So given that [2] compiles and works, and [1] can be used as a limited work-around for the offsetof case (at least in my case [1] is enough), I wonder if it can be considered as a possible extension.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #25 from mark --- As suggested, I've posted my comments as a question to the gcc-help mailing list, viewable at https://gcc.gnu.org/ml/gcc-help/2020-02/msg00048.html Further comments and suggestions are welcome as replies on the list. Thanks.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #24 from comexk at gmail dot com --- > All that's needed for that is an extension to provide a compile-time > constant value to a pointer, not to allow arbitrary reinterpret_casts in > constexpr. Well, there aren't that many things that reinterpret_cast can do. Casting pointers to different pointer types would be useful, but using such pointers is normally undefined behavior anyway. The exception is accessing byte representations using `char *` pointers. Supporting that in constexpr context *would* be a major feature, but it doesn't need to be allowed just because the cast itself is allowed. On the other hand, C++20 is adding an alternate way to manipulate byte representations in constexpr context, std::bit_cast. (It's non-constexpr when the types involved contain unions or pointers, so it can't be used directly in place of reinterpret_cast.) Most of the work that would be needed to support access-through-`char *` as an extension needs to be done anyway for std::bit_cast; on the other hand, its existence reduces the need for an extension. Regardless, it would be nice to lift the pointer restriction on std::bit_cast as an extension.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #23 from Jonathan Wakely --- What you want (and what everybody I've seen asking for similar things) is to give a compile-time constant value to a pointer. All that's needed for that is an extension to provide a compile-time constant value to a pointer, not to allow arbitrary reinterpret_casts in constexpr. A more limited extension that solves the problem is a lot more reasonable.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #22 from Jonathan Wakely --- (In reply to mark from comment #21) > The behavior here is non-portable, but well defined. If it wasn't, the > runtime reinterpret_cast would also be undefined. Why are/should constant > expressions be different? https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion is a better place to ask that. GCC's bugzilla is not the place for it. > (In reply to Jonathan Wakely from comment #20) > > And doesn't exactly the same thing work fine in C++? > I don't understand the point. Yes, a C++ compiler will accept the C code. > But it will still be C, without the object-oriented advantages of C++ (the C > code has external functions taking struct pointers instead of instance > methods, etc, etc.) If you want member functions, this works fine: struct Addr { unsigned* const u; void set() const { *u = 0x87654321; } }; struct Addr addr = { (unsigned*)0x4000 }; int main() { addr.set(); } > As I illustrated, it's impossible to have a C++ class > with an unsigned* const member pointing to an arbitrary memory address -- > and still have the object constexpr constructed/initialized in .data -- as > it is in C. See above.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #21 from mark --- (In reply to Jonathan Wakely from comment #19) > The main reason is that reinterpret_cast subverts the type system. > Constant expressions have to be free of undefined behaviour, which is > impossible to do if arbitrary nonsense^W code that violates the type > system is supported. Sorry, I still don't understand. Yes, reinterpret_cast subverts the type system. In this case that's intentional, as there's no other way (that I know) to have an arbitrary class pointer to an arbitrary memory address. (I've tried placement new without success.) The behavior here is non-portable, but well defined. If it wasn't, the runtime reinterpret_cast would also be undefined. Why are/should constant expressions be different? (In reply to Jonathan Wakely from comment #20) > And doesn't exactly the same thing work fine in C++? I don't understand the point. Yes, a C++ compiler will accept the C code. But it will still be C, without the object-oriented advantages of C++ (the C code has external functions taking struct pointers instead of instance methods, etc, etc.) As I illustrated, it's impossible to have a C++ class with an unsigned* const member pointing to an arbitrary memory address -- and still have the object constexpr constructed/initialized in .data -- as it is in C. BTW, I am very committed to strong type-safe system design. See my FOSS repositories at https://github.com/thanks4opensource/regbits and https://github.com/thanks4opensource/regbits_stm for examples. It is precisely the inability to constexpr construct a class containing an Object* const pointer (or, alternately, a reference) to an instantiation of the class templates in those systems that led to this request -- the unsigned* examples I used here were for minimal/clear illustration. As always, I appreciate the feedback, and would welcome any solution within the current standard that satisfied all the requirements I've laid out. I have researched the topic online without finding anything other than the workaround I described.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #20 from Jonathan Wakely --- (In reply to mark from comment #18) > And of course none of this is needed when coding in C instead of C++. The > following struct is placed in .data without any workarounds being required: And doesn't exactly the same thing work fine in C++?
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #19 from Jonathan Wakely --- The main reason is that reinterpret_cast subverts the type system. Constant expressions have to be free of undefined behaviour, which is impossible to do if arbitrary nonsense^W code that violates the type system is supported.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 mark changed: What|Removed |Added CC||markrubn at yahoo dot com --- Comment #18 from mark --- I'd also like to request a GCC extension to allow reinterpret_cast in a constexpr. Following are a question, a comment, and a use-case illustrating why the extension is needed. Question: I understand that using reinterpret_cast in a constexpr is disallowed by the C++ standard. *Why* is it disallowed? The only reason I've seen stated is that "reinterpret_cast may require runtime (hardware) support". That seems plausible, but a constexpr static_cast from int to double, which requires a far deeper understanding of the target architecture, is supported. I understand that int-to-pointer conversion may involve widening, narrowing, or even more complex and possibly inexpressible semantics (segmented/non-linear memory architectures), but reinterpret_cast by definition is non-portable and error prone. Its "use these bits as they are" semantics, with possible truncation or zero-padding, seems to allow it to be used unambiguously in most normal cases. Comment: GCC has never been "shy" about adding extensions. Some of them, like __attribute__((fallthrough) becoming [[fallthrough]], have even eventually made it into the standards. Use-case: It is common practice in embedded microcontrollers to access hardware resources via reads and writes to specific, fixed memory addresses. I believe this is generally understood but can provide much more detail if requested. In addition, microcontrollers are usually very limited in terms of memory and CPU speed. By using constexpr constructors, extern/static objects are compiled pre-initialized in the .data segment, eliminating the memory needed for pre-main() constructor code and the time to execute it. In GCC 4.8.3, prior to the changes to make GCC standards-compliant as described in this bug report, the following code would compile the object into .data segment: ``` class C { public: constexpr C( unsigned* const u) : _u(u) {} void set() const { *_u = 0x87654321; } protected: unsigned* const _u; }; unsigned* const addr = reinterpret_cast(0x4000); C c(addr); int main() { c.set(); } ``` Later versions compile the object into .bss, and also include C::C constructor code. Attempts to force constexpr construction by changing the above to: ``` constexpr unsigned* const addr = reinterpret_cast(0x4000); ``` causes no change with 4.8.3 but results in a fatal "error: value ‘1073741824’ of type ‘unsigned int*’ is not a constant expression" in later versions. The only workaround I know is to introduce an extra conversion method, which will then again compile the object into .data with no runtime construction required: ``` class Addr { public: constexpr Addr( unsigned const u_addr) : _u_addr(u_addr) {} void set() const { *_u() = 0x87654321; } protected: volatile unsigned* _u() const { return reinterpret_cast(_u_addr);} unsigned const _u_addr; }; Addr addr(0x4000); int main() { addr.set(); } ``` And of course none of this is needed when coding in C instead of C++. The following struct is placed in .data without any workarounds being required: ``` struct Addr { unsigned* const u; }; void set( struct Addr *a) { *(a->u) = 0x87654321; } struct Addr addr = { (unsigned*)0x4000 }; int main() { set(); } ``` I firmly believe that C++ offers important improvements over C, with few if any disadvantages. Many in the embedded programming community feel otherwise ("C++ is obfuscated") and in this example the objection is valid. Any comments, corrections, or responses -- much less a change so that -fpermissive allows the reinterpret_cast -- would be welcome. Thank you.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 Stas Sergeev changed: What|Removed |Added CC||stsp at users dot sourceforge.net --- Comment #17 from Stas Sergeev --- The following code now breaks: --- #include #include template struct offset_of { constexpr operator size_t() const { return (std::uintptr_t)&(static_cast(nullptr)->*M); } }; template struct B { char aa[10]; static const int off = offset_of(); }; struct A { char a; char _mark[0]; B b; }; int main() { A a; std::cout << "size " << sizeof(A) << " off " << a.b.off << std::endl; return 0; } --- There is no other way of making offsetof(), rather than by a reinterpret cast in constexpr (unless you try very hard - I was still able to work around these new gcc checks, but its tricky). Would you consider adding this into -fpremissive? Suddenly removing an extensions that people got used to, is not the best treatment of users, AFAICT. Isn't -fpermissive a right place for the extensions that people got used to?
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 comexk at gmail dot com changed: What|Removed |Added CC||comexk at gmail dot com --- Comment #16 from comexk at gmail dot com --- IMHO it would be very useful to have an extension to force the compiler to accept these casts, and anything else that GCC is capable of constant-evaluating but the standard overly-conservatively rejects.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 Jakub Jelinek changed: What|Removed |Added Status|NEW |RESOLVED CC||jakub at gcc dot gnu.org Resolution|--- |FIXED --- Comment #15 from Jakub Jelinek --- Fixed for 8.1+.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #14 from Jakub Jelinek --- Author: jakub Date: Wed Apr 25 07:10:16 2018 New Revision: 259629 URL: https://gcc.gnu.org/viewcvs?rev=259629=gcc=rev Log: PR c++/85437 PR c++/49171 * cp-tree.h (REINTERPRET_CAST_P): New. * constexpr.c (cxx_eval_constant_expression) : Reject REINTERPET_CAST_P conversions. Use cplus_expand_constant for non-trivial PTRMEM_CST cases. * typeck.c (build_nop_reinterpret): New. (build_reinterpret_cast_1): Use it. Set REINTERPRET_CAST_P on NOP_EXPRs returned by cp_convert. * g++.dg/cpp0x/addressof1.C: Make reinterpret cases runtime checks. * g++.dg/cpp0x/constexpr-cast.C: Remove xfails * g++.dg/cpp0x/constexpr-nullptr-2.C: Likewise. * g++.dg/cpp0x/constexpr-pmf1.C: Check when optimized. * g++.dg/cpp0x/pr85437-1.C: New. * g++.dg/cpp0x/pr85437-2.C: New. * g++.dg/cpp0x/pr85437-3.C: New. * g++.dg/cpp0x/pr85437-4.C: New. Added: trunk/gcc/testsuite/g++.dg/cpp0x/pr85437-1.C trunk/gcc/testsuite/g++.dg/cpp0x/pr85437-2.C trunk/gcc/testsuite/g++.dg/cpp0x/pr85437-3.C trunk/gcc/testsuite/g++.dg/cpp0x/pr85437-4.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/constexpr.c trunk/gcc/cp/cp-tree.h trunk/gcc/cp/typeck.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/g++.dg/cpp0x/addressof1.C trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-nullptr-2.C trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-pmf1.C
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 Martin Sebor changed: What|Removed |Added CC||msebor at gcc dot gnu.org --- Comment #13 from Martin Sebor --- The latest C++ working draft (N4582 from March 2016) makes it clear that reinterpret_cast cannot be evaluated in core constant expressions. AFAICS, this restriction hasn't changed since C++ 11. The current top of trunk (GCC 7.0) and prior released versions still accept reinterpret_cast in constexpr contexts, including the expression in comment #0. In my work on bug 60760 I looked into how feasible it would be to reject reinterpret_cast in constexpr contexts. Rejecting examples like the one in comment #0 is doable because a non-zero integer constant can only be converted to a pointer by a reinterpret_cast, but rejecting others, such as int i constexpr void *p = reinterpret_cast(); looks harder because the representation of this cast (a NOP_EXPR) is indistinguishable from that of the following valid core constant expression: constexpr void *p = The fact that one was the result of a reinterpret_cast and another of implicit conversion is long lost by the time it's interpreted in a constexpr context. To distinguish the two expressions, their internal representation would need to be different.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 Melissa myriachan at gmail dot com changed: What|Removed |Added CC||myriachan at gmail dot com --- Comment #12 from Melissa myriachan at gmail dot com --- (In reply to Kai Tietz from comment #11) Fixed with delayed-folding for C++. Therefore mine. Why fix it? The Standard doesn't allow it, but it's still useful. For example, std::numeric_limitsfloat::infinity() cannot be implemented without it or compiler magic (e.g. __builtin_huge_valf in the current libstdc++). Melissa
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 Kai Tietz ktietz at gcc dot gnu.org changed: What|Removed |Added Assignee|unassigned at gcc dot gnu.org |ktietz at gcc dot gnu.org --- Comment #11 from Kai Tietz ktietz at gcc dot gnu.org --- Fixed with delayed-folding for C++. Therefore mine.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 Jason Merrill jason at gcc dot gnu.org changed: What|Removed |Added CC||jason at gcc dot gnu.org, ||ktietz at gcc dot gnu.org --- Comment #10 from Jason Merrill jason at gcc dot gnu.org --- This is another one to fix with Kai's delayed folding work.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 Paolo Carlini paolo.carlini at oracle dot com changed: What|Removed |Added Status|UNCONFIRMED |NEW Last reconfirmed||2012-10-23 CC|paolo.carlini at oracle dot | |com | Blocks||55004 Ever Confirmed|0 |1
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #9 from Paolo Carlini paolo.carlini at oracle dot com 2012-10-23 23:02:31 UTC --- Per Comment #3 in PR55039, I think we have simply to reject reinterpret_casts.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #7 from Paolo Carlini paolo.carlini at oracle dot com 2012-10-05 14:10:11 UTC --- Thanks a lot Daniel for the clarification. Thus I understand that currently GCC is accepting *all sorts* of reinterpret_cast uses in constexpr functions, right? That is, also those with unspecified result?
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #8 from Daniel Krügler daniel.kruegler at googlemail dot com 2012-10-05 14:17:18 UTC --- (In reply to comment #7) Thus I understand that currently GCC is accepting *all sorts* of reinterpret_cast uses in constexpr functions, right? That is, also those with unspecified result? Correct. The introductory example belongs to this family, for example.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 Paolo Carlini paolo.carlini at oracle dot com changed: What|Removed |Added CC||paolo.carlini at oracle dot ||com --- Comment #3 from Paolo Carlini paolo.carlini at oracle dot com 2012-10-03 14:27:50 UTC --- Daniel, what's the status of this issue? Is there some consensus that GCC is actually Ok, we don't really want to reject reinterpret_casts? Because I would find very useful a constexpr std::addressof. For the time being we could certainly have it constexpr anyway and change the implementation details when/if the C++ front-end starts rejecting reintepret_casts, but I would rather not.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #4 from Daniel Krügler daniel.kruegler at googlemail dot com 2012-10-03 16:22:24 UTC --- (In reply to comment #3) Daniel, what's the status of this issue? Is there some consensus that GCC is actually Ok, we don't really want to reject reinterpret_casts? My opinion is that gcc should start to implement the new core rules in regard to reinterpret_cast *except* for cases that are well-defined. Because I would find very useful a constexpr std::addressof. For the time being we could certainly have it constexpr anyway and change the implementation details when/if the C++ front-end starts rejecting reintepret_casts, but I would rather not. Exactly this usage of reinterpret_cast seems IMO to be well granted by the standard - at least by the way I read it.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #5 from Paolo Carlini paolo.carlini at oracle dot com 2012-10-03 16:46:30 UTC --- Ok, thanks. Sorry about the naive question: is it already clear what it means for reinterpret_cast uses to be well-defined in this sense?
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #6 from Daniel Krügler daniel.kruegler at googlemail dot com 2012-10-03 18:46:09 UTC --- (In reply to comment #5) Ok, thanks. Sorry about the naive question: is it already clear what it means for reinterpret_cast uses to be well-defined in this sense? This is surely no naive question. I should have been more specific: I think only those reinterpret_cast operations that have a *specified* result, should be allowed (similar to relational or equality operations). For example An expression of integral, enumeration, pointer, or pointer-to-member type can be explicitly converted to its own type; such a cast yields the value of its operand. seems well specified and uncontroversial to me. Another example (and this is relevant for std::addressof) is the combination of p7 An object pointer can be explicitly converted to an object pointer of a different type. [..] Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. and p11 An lvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast. That is, a reference cast reinterpret_castT(x) has the same effect as the conversion *reinterpret_castT*(x) with the built-in and * operators (and similarly for reinterpret_castT(x)). In other words, the whole expression reinterpret_castT*(const_castchar( reinterpret_castconst volatile char(t))) that is typically used for the real address deduction seems to have well-specified behaviour and should thus be constexpr-friendly.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #2 from Daniel Krügler daniel.kruegler at googlemail dot com 2011-08-30 09:39:43 UTC --- I believe I found a conforming usage of reinterpret_cast in constant expressions useable in C++03: // struct X { X* operator(); }; X x[2]; const bool p = (reinterpret_castX*(reinterpret_castchar(x[1])) - reinterpret_castX*(reinterpret_castchar(x[0]))) == sizeof(X); enum E { e = p }; // e should have a value equal to 1 // Basically this program demonstrates the technique, the C++11 library function addressof is based on and thus excluding reinterpret_cast *unconditionally* from constant expressions in the core language would render this useful program invalid and would make it impossible to declare addressof as a constexpr function.
[Bug c++/49171] [C++0x][constexpr] Constant expressions support reinterpret_cast
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49171 --- Comment #1 from Daniel Krügler daniel.kruegler at googlemail dot com 2011-05-26 12:10:59 UTC --- Additional remark: I'm speaking of potential code breakages that did rely on non-portable behaviour, because there is no evidence for me that C++03 did support this kind of reinterpret_cast usage.