research: investigate narrowing conversion problem

as it turns out, this is a Bug in GCC 4.9 (resolved in 5.x)
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63723

Problem is, GCC emits a warning on narrowing conversions,
while the standard actually disallows them when building
objects from brace-enclosed initialisers.

Unfortunately GCC also emits such a warning from within
a SFINAE context, instead of letting those spurious dangerous
cases fail. So we end up with additional visitor double dispatch
paths, and a lot of additional warnings.

Temporary solution is to hack a custom trait, which
explicitly declares some conversions paths as "narrowing".
Probably this can be implemented in a way more intelligent
way (using std::numeric_limits), but this doesn't seem
worth the effort, since the problem will go away through
compiler evolution eventually.
This commit is contained in:
Fischlurch 2016-01-24 13:44:12 +01:00
parent f4bcdcf4e8
commit 1cbebb1fab
2 changed files with 164 additions and 11 deletions

View file

@ -80,12 +80,99 @@ using std::tuple;
namespace error = lumiera::error;
//////////////////////////////////////TODO traits
namespace lib {
namespace meta {
using std::is_constructible;
using std::is_unsigned;
using std::is_signed;
using std::is_floating_point;
template<typename NUM>
struct is_nonFloat
: __and_<is_arithmetic<NUM>
,__not_<is_floating_point<NUM>>
>
{ };
/** temporary workaround for GCC [Bug-63723], necessary until CGG-5
* @remarks The problem is that GCC emits a warning on narrowing conversion,
* instead of letting the SFINAE substitution fail. This can be considered
* questionable behaviour, since the usual implementation of a `is_convertible`
* trait uses initialisation from a brace enclosed list, where C++11 prohibits
* narrowing conversions. Now the problem is, that we'll use such traits checks
* to remove such _impossble_ cases from generated trampoline tables or visitor
* double dispatch implementations. Thus, for one we get lots of warnings at that
* point when generating those trampoline tables (at initialisation), while it
* is not clear we'll trigger those cases, and, when we do, we'll get narrowing
* conversions in a context where we're unable to cope with them or protect
* ourselves against spurious conversions.
* What follows is a quick-n-dirty hack to remove such unwanted conversions.
*
* [Bug-63723]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63723
*/
template<typename SRC, typename TAR>
struct is_narrowingInit
: __or_<__and_<is_unsigned<SRC>, is_signed<TAR>>
,__and_<is_signed<SRC>, is_unsigned<TAR>>
,__and_<is_nonFloat<SRC>, is_floating_point<TAR>>
,__and_<is_floating_point<SRC>, is_nonFloat<TAR>>
,__not_<is_constructible<TAR, SRC>>
>
{ };
#define TRAIT_IS_NARROWING(_SRC_, _TAR_) \
template<> \
struct is_narrowingInit<_SRC_, _TAR_> \
: std::true_type \
{ };
TRAIT_IS_NARROWING (int64_t, int32_t)
TRAIT_IS_NARROWING (int64_t, int16_t)
TRAIT_IS_NARROWING (int64_t, int8_t)
TRAIT_IS_NARROWING (int32_t, int16_t)
TRAIT_IS_NARROWING (int32_t, int8_t)
TRAIT_IS_NARROWING (int16_t, int8_t)
TRAIT_IS_NARROWING (int16_t, short)
TRAIT_IS_NARROWING (int16_t, char)
TRAIT_IS_NARROWING (uint64_t, uint32_t)
TRAIT_IS_NARROWING (uint64_t, uint16_t)
TRAIT_IS_NARROWING (uint64_t, uint8_t)
TRAIT_IS_NARROWING (uint32_t, uint16_t)
TRAIT_IS_NARROWING (uint32_t, uint8_t)
TRAIT_IS_NARROWING (uint16_t, uint8_t)
TRAIT_IS_NARROWING (uint16_t, ushort)
TRAIT_IS_NARROWING (double, float)
TRAIT_IS_NARROWING (lib::hash::LuidH, int64_t)
TRAIT_IS_NARROWING (lib::hash::LuidH, int32_t)
TRAIT_IS_NARROWING (lib::hash::LuidH, int16_t)
TRAIT_IS_NARROWING (lib::hash::LuidH, int8_t)
TRAIT_IS_NARROWING (lib::hash::LuidH, char)
TRAIT_IS_NARROWING (lib::hash::LuidH, uint16_t)
TRAIT_IS_NARROWING (lib::hash::LuidH, uint8_t)
TRAIT_IS_NARROWING (lib::hash::LuidH, double)
TRAIT_IS_NARROWING (lib::hash::LuidH, float)
#undef TRAIT_IS_NARROWING
}} //////////////////////////////////////TODO traits
using std::__not_;
using std::__and_;
using std::__or_;
using std::is_constructible;
using lib::meta::is_narrowingInit;
using lib::meta::Strip;
using DataCapPredicate = Variant<DataValues>::Predicate;
template<typename TAR>
class GenNodeAccessor
struct GenNodeAccessor
: boost::noncopyable
{
struct ConverterBase
@ -107,11 +194,16 @@ class GenNodeAccessor
};
template<typename TY>
using can_Convert = std::is_constructible<TAR, TY const&>;
struct allow_Conversion
: __and_<is_constructible<TAR, TY const&>
,__not_<is_narrowingInit<typename Strip<TY>::TypePlain
,typename Strip<TAR>::TypePlain>>
>
{ };
using PossibleSourceTypes = typename Filter<DataValues::List, can_Convert>::List;
using SupportedSourceTypes = typename Filter<DataValues::List, allow_Conversion>::List;
using ConversionBuffer = InstantiateChained< PossibleSourceTypes
using ConversionBuffer = InstantiateChained< SupportedSourceTypes
, Converter
, ConverterBase
>;
@ -133,7 +225,7 @@ class GenNodeAccessor
}
};
//////////TODO this goes into typeseq-util.hpp
template<class, size_t>
struct Pick;
@ -221,13 +313,47 @@ buildTuple (SRC values)
#define SHOW_TYPE(_TY_) \
cout << "typeof( " << STRINGIFY(_TY_) << " )= " << lib::meta::typeStr<_TY_>() <<endl;
#define EVAL_PREDICATE(_PRED_) \
cout << STRINGIFY(_PRED_) << "\t : " << _PRED_ <<endl;
void
verifyConversions()
{
using std::is_arithmetic;
using std::is_floating_point;
using lib::meta::is_nonFloat;
using lib::hash::LuidH;
EVAL_PREDICATE(is_arithmetic<int> ::value)
EVAL_PREDICATE(is_arithmetic<size_t> ::value)
EVAL_PREDICATE(is_floating_point<size_t>::value)
EVAL_PREDICATE(is_nonFloat<size_t> ::value)
EVAL_PREDICATE(GenNodeAccessor<int> ::allow_Conversion<size_t> ::value)
EVAL_PREDICATE(GenNodeAccessor<int64_t>::allow_Conversion<long int>::value)
EVAL_PREDICATE(GenNodeAccessor<double>::allow_Conversion<int64_t>::value)
EVAL_PREDICATE(GenNodeAccessor<LuidH>::allow_Conversion<int64_t> ::value)
EVAL_PREDICATE(GenNodeAccessor<LuidH>::allow_Conversion<int16_t> ::value)
EVAL_PREDICATE(GenNodeAccessor<LuidH>::allow_Conversion<uint16_t>::value)
EVAL_PREDICATE(GenNodeAccessor<LuidH> ::allow_Conversion<LuidH> ::value)
EVAL_PREDICATE(GenNodeAccessor<int64_t> ::allow_Conversion<LuidH>::value)
EVAL_PREDICATE(GenNodeAccessor<uint64_t>::allow_Conversion<LuidH>::value)
EVAL_PREDICATE(GenNodeAccessor<uint32_t>::allow_Conversion<LuidH>::value)
EVAL_PREDICATE(GenNodeAccessor<int32_t> ::allow_Conversion<LuidH>::value)
cout <<endl<<endl;
}
int
main (int, char**)
{
using NiceTypes = Types<string, int>;
using UgglyTypes = Types<EntryID<long>, string, short, long, float, TimeVar>;
verifyConversions();
using NiceTypes = Types<string, int>;
using UgglyTypes = Types<EntryID<long>, string, int, int64_t, double, TimeVar>;
Rec args = MakeRec().scope("lalü", 42);
Rec urgs = MakeRec().scope("lalü", "lala", 12, 34, 5.6, Time(7,8,9));

View file

@ -734,7 +734,7 @@
<node CREATED="1453546417098" ID="ID_676713402" MODIFIED="1453546563455" TEXT="DOM vs. compiletime typing">
<icon BUILTIN="info"/>
</node>
<node CREATED="1453546436455" ID="ID_129001401" MODIFIED="1453546551564" TEXT="double-dispatch">
<node CREATED="1453546436455" FOLDED="true" ID="ID_129001401" MODIFIED="1453639145606" TEXT="double-dispatch">
<icon BUILTIN="idea"/>
<node CREATED="1453546450317" ID="ID_1899026394" MODIFIED="1453590519383" TEXT="Variant-Visitor">
<icon BUILTIN="button_ok"/>
@ -749,12 +749,39 @@
</node>
<node CREATED="1453590522161" ID="ID_1369411965" MODIFIED="1453590545513" TEXT="Problem: narrowing conversions">
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#990000" CREATED="1453590566651" ID="ID_1367428687" MODIFIED="1453590610375" TEXT="TODO">
<icon BUILTIN="flag"/>
</node>
<node CREATED="1453590585865" ID="ID_350595711" MODIFIED="1453590606670" TEXT="explizit gef&#xe4;hrliche ausschlie&#xdf;en">
<icon BUILTIN="yes"/>
</node>
<node CREATED="1453638973049" ID="ID_1350801390" LINK="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63723" MODIFIED="1453639023645">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
Compiler-Bug <font color="#c80219">Gcc-#63723</font>
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1453639033250" ID="ID_1669831951" LINK="http://stackoverflow.com/questions/26705199/how-can-i-write-a-type-trait-to-check-if-a-type-is-convertible-to-another-by-a-n" MODIFIED="1453639049952" TEXT="s.a. Stackoverflow"/>
<node CREATED="1453639055478" ID="ID_1560466275" MODIFIED="1453639078468">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
gel&#246;st in GCC-5 --&#160;<i>backport unwahrscheinlich</i>
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1453639119142" ID="ID_1472487058" MODIFIED="1453639126177" TEXT="inzwischen hartgecodet">
<icon BUILTIN="clanbomber"/>
</node>
</node>
<node CREATED="1453546467707" ID="ID_1543497504" MODIFIED="1453546472446" TEXT="Problem: template bloat">
<node CREATED="1453590622236" ID="ID_1084684065" MODIFIED="1453590761460" TEXT="h&#xe4;lt sich in Grenzen">