Vitaliy, thank you for investigating that, and for reporting it to Microsoft! In the meantime, we can implement the simple workaround Kenton described. I will do so later this week, unless you beat me to it. :)
On Tue, Feb 28, 2017 at 4:10 AM, Vitaliy Bondarchuk < [email protected]> wrote: > i filled feedback form in the VS with this data and sent it to VS team. > hope they will fix > > вторник, 28 февраля 2017 г., 13:23:34 UTC+2 пользователь Vitaliy > Bondarchuk написал: > >> hi Kenton >> >> yes, when you initialize by explicit value (number or literal) - it works >> better then when you initialize by return value of a function >> look please here: >> >> header.h ============== >> pragma once >> >> namespace test >> { >> typedef unsigned int uint; >> typedef uint BitCount; >> >> template <typename T> inline constexpr T f1() { return T(0x12345678); } >> constexpr BitCount v1 = f1<BitCount>(); >> >> constexpr BitCount v2 = 0x12345678; >> >> inline constexpr unsigned int f3() { return 0x12345678; } >> constexpr BitCount v3 = f3(); >> >> constexpr auto v4 = "1234567890qwertyuiopasdfghjklzxcvbnm"; >> >> inline constexpr auto f5() { return "1234567890qwertyuiopasdfghjklzxcvbnm"; >> } >> constexpr auto v5 = f5(); >> >> struct S >> { >> char a[4096]; >> }; >> inline constexpr auto f6() { return S(); } >> constexpr auto v6 = f6(); >> >> template <typename T> constexpr T f7 = { 1 }; >> constexpr BitCount v7 = f7<BitCount>; >> >> constexpr BitCount v9 = 0x12345678; //address of this is taken in the >> main() >> } >> ==================================== >> ConsoleApplication1.cpp ================== >> #include "stdafx.h" >> #include "Header.h" >> int main() >> { >> auto v10 = &test::v9; >> >> printf("1=%p\n", v10); >> return 0; >> } >> ==================================== >> Source.cpp ================== >> #include "stdafx.h" >> #include "Header.h" >> ==================================== >> resulting map: >> >> >> <https://lh3.googleusercontent.com/-pmJCKfJvUkg/WLVcr0774vI/AAAAAAAABrM/snp2E2sBU7AlprKABT0KY5XDOniKiNfiACLcB/s1600/Untitled.jpg> >> >> The compiler from VS version 14.0.25431.01 Update 3 >> Map analyzing tool http://www.sikorskiy.net/prj/amap/ >> The test project attached :) >> >> >> >> >> понедельник, 27 февраля 2017 г., 23:10:04 UTC+2 пользователь Kenton Varda >> написал: >>> >>> Oh wow, I didn't realize on my first read that the initialization >>> expression makes a difference -- if it's just the value `1` rather than >>> `kj::unit<T>()` then it gets elided properly? That's really strange! Since >>> it is a constexpr, the compiler really ought to be evaluating and >>> substituting the expression with the raw value at compile time, so that >>> they are treated identically. I guess this is another symptom of MSVC's >>> constexpr support being poor. >>> >>> But I guess this means there's an easy solution: Move the declarations >>> of BITS, BYTES, etc. up into the #ifdef CAPNP_DEBUG_TYPES right above where >>> they are declared currently. For the non-debug-types branch, initialize >>> them all to `1` rather than `kj::unit<T>()`. >>> >>> Happy to accept such a PR. >>> >>> -Kenton >>> >>> On Mon, Feb 27, 2017 at 12:59 PM, Harris Hancock <[email protected]> >>> wrote: >>> >>>> It does sound like a disappointing MSVC bug. Perhaps C++14 variable >>>> templates generate better MSVC output? Something like: >>>> >>>> template <typename T> constexpr T unit {1}; >>>> constexpr BitCount BITS = unit<BitCount>; >>>> >>>> If so, that could be part of a solution. I'll test when I can. >>>> >>>> Harris >>>> >>>> On Mon, Feb 27, 2017 at 11:36 AM, Kenton Varda <[email protected]> >>>> wrote: >>>> >>>>> Hi Vitaliy, >>>>> >>>>> Hmm, this seems like a pretty big bug in MSVC. It should be >>>>> de-duplicating constants across object files, and it should be eliding the >>>>> ones that aren't used. >>>>> >>>>> Note that these constants are only simple integers if you aren't >>>>> defining CAPNP_DEBUG_TYPES. If CAPNP_DEBUG_TYPES is defined then these >>>>> constants have special types that perform unit analysis, and your example >>>>> code would not compile. >>>>> >>>>> I don't see how we can avoid defining the constants in a release >>>>> build. They are used all over in the Cap'n Proto implementation. But it's >>>>> very surprising to me that MSVC can't handle elide simple integer >>>>> constants. >>>>> >>>>> Harris, do you have any thoughts? >>>>> >>>>> -Kenton >>>>> >>>>> On Mon, Feb 27, 2017 at 3:07 AM, Vitaliy Bondarchuk < >>>>> [email protected]> wrote: >>>>> >>>>>> hi >>>>>> >>>>>> VS2015 (update pack 3) compiler produced own copy of these constants >>>>>> in each object file: >>>>>> constexpr BitCount BITS = kj::unit<BitCount>(); >>>>>> constexpr ByteCount BYTES = kj::unit<ByteCount>(); >>>>>> constexpr WordCount WORDS = kj::unit<WordCount>(); >>>>>> constexpr ElementCount ELEMENTS = kj::unit<ElementCount>(); >>>>>> constexpr WirePointerCount POINTERS = kj::unit<WirePointerCount>(); >>>>>> >>>>>> As example map file of resulted binary tell me that I have 22 copies >>>>>> of capnp::BITS in it. 88 bytes is not a big deal, but... it's a bit >>>>>> inaccurate ) >>>>>> And this happens when the header visible to just 17 my cpp files. And >>>>>> a cpp file doesn't need even use a constant - include the header enough >>>>>> for >>>>>> produce variable in the object file. >>>>>> >>>>>> As I understand you use it for special types in DEBUG build. >>>>>> But can it be a bit more trivial for RELEASE? >>>>>> >>>>>> I tried simple project with the header: >>>>>> >>>>>> namespace kj >>>>>> { >>>>>> template <typename T> >>>>>> inline constexpr T unit() { return T(1); } >>>>>> >>>>>> inline constexpr unsigned int unit3() { return 1; } >>>>>> } >>>>>> >>>>>> namespace capnp >>>>>> { >>>>>> typedef unsigned int uint; >>>>>> typedef uint BitCount; >>>>>> >>>>>> constexpr BitCount BITS1 = kj::unit<BitCount>(); >>>>>> constexpr BitCount BITS2 = 1; >>>>>> constexpr BitCount BITS3 = kj::unit3(); >>>>>> } >>>>>> >>>>>> all 3 constants have value 1. and all 3 properly can be used as size >>>>>> of an array >>>>>> #include "Header.h" >>>>>> >>>>>> void f(); >>>>>> >>>>>> int main() >>>>>> { >>>>>> int b1[capnp::BITS1] = {}; >>>>>> int b2[capnp::BITS2] = {}; >>>>>> int b3[capnp::BITS3] = {}; >>>>>> f(); >>>>>> >>>>>> printf("1=%d 2=%d 3=%d\n", capnp::BITS1, capnp::BITS2, capnp::BITS3); >>>>>> >>>>>> return 0; >>>>>> } >>>>>> >>>>>> but the map file is: >>>>>> 3 .bss 62c 4 unsigned int const capnp::BITS1 ConsoleApplication1.obj >>>>>> ?BITS1@capnp@@3IB >>>>>> 3 .bss 630 4 unsigned int const capnp::BITS3 ConsoleApplication1.obj >>>>>> ?BITS3@capnp@@3IB >>>>>> 3 .bss 634 4 unsigned int const capnp::BITS1 Source.obj ?BITS1@capnp >>>>>> @@3IB >>>>>> 3 .bss 638 8 unsigned int const capnp::BITS3 Source.obj ?BITS1@capnp >>>>>> @@3IB >>>>>> >>>>>> >>>>>> -- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "Cap'n Proto" group. >>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>> send an email to [email protected]. >>>>>> Visit this group at https://groups.google.com/group/capnproto. >>>>>> >>>>> >>>>> >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "Cap'n Proto" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to [email protected]. >>>> Visit this group at https://groups.google.com/group/capnproto. >>>> >>> >>> -- You received this message because you are subscribed to the Google Groups "Cap'n Proto" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. Visit this group at https://groups.google.com/group/capnproto.
