From 1cbebb1fabe90d5236809ac1f9db25f522fab720 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 24 Jan 2016 13:44:12 +0100 Subject: [PATCH] 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. --- research/try.cpp | 140 +++++++++++++++++++++++++++++++++++++-- wiki/thinkPad.ichthyo.mm | 35 ++++++++-- 2 files changed, 164 insertions(+), 11 deletions(-) diff --git a/research/try.cpp b/research/try.cpp index fa95967bb..59eb6397b 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -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 + struct is_nonFloat + : __and_ + ,__not_> + > + { }; + + /** 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 + struct is_narrowingInit + : __or_<__and_, is_signed> + ,__and_, is_unsigned> + ,__and_, is_floating_point> + ,__and_, is_nonFloat> + ,__not_> + > + { }; + +#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::Predicate; template -class GenNodeAccessor +struct GenNodeAccessor : boost::noncopyable { struct ConverterBase @@ -107,11 +194,16 @@ class GenNodeAccessor }; template - using can_Convert = std::is_constructible; + struct allow_Conversion + : __and_ + ,__not_::TypePlain + ,typename Strip::TypePlain>> + > + { }; - using PossibleSourceTypes = typename Filter::List; + using SupportedSourceTypes = typename Filter::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 struct Pick; @@ -221,13 +313,47 @@ buildTuple (SRC values) #define SHOW_TYPE(_TY_) \ cout << "typeof( " << STRINGIFY(_TY_) << " )= " << lib::meta::typeStr<_TY_>() < ::value) + EVAL_PREDICATE(is_arithmetic ::value) + EVAL_PREDICATE(is_floating_point::value) + EVAL_PREDICATE(is_nonFloat ::value) + + EVAL_PREDICATE(GenNodeAccessor ::allow_Conversion ::value) + EVAL_PREDICATE(GenNodeAccessor::allow_Conversion::value) + EVAL_PREDICATE(GenNodeAccessor::allow_Conversion::value) + EVAL_PREDICATE(GenNodeAccessor::allow_Conversion ::value) + EVAL_PREDICATE(GenNodeAccessor::allow_Conversion ::value) + EVAL_PREDICATE(GenNodeAccessor::allow_Conversion::value) + EVAL_PREDICATE(GenNodeAccessor ::allow_Conversion ::value) + EVAL_PREDICATE(GenNodeAccessor ::allow_Conversion::value) + EVAL_PREDICATE(GenNodeAccessor::allow_Conversion::value) + EVAL_PREDICATE(GenNodeAccessor::allow_Conversion::value) + EVAL_PREDICATE(GenNodeAccessor ::allow_Conversion::value) + + cout <; - using UgglyTypes = Types, string, short, long, float, TimeVar>; + verifyConversions(); + using NiceTypes = Types; + using UgglyTypes = Types, 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)); diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 1ae8e82ab..990212dbc 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -734,7 +734,7 @@ - + @@ -749,12 +749,39 @@ - - - + + + + + + +

+ Compiler-Bug Gcc-#63723 +

+ + +
+
+ + + + + + + +

+ gelöst in GCC-5 -- backport unwahrscheinlich +

+ + +
+
+ + +