Hi,
after more than 2 years, I'm finally back to this issue:
https://gcc.gnu.org/ml/gcc-patches/2012-05/msg01442.html
https://gcc.gnu.org/ml/gcc-patches/2012-05/msg01502.html
and the below draft, which passes testing, tries to implement as closely
as possible what Jason suggested in the thread above. How does it look?
Thanks!
Paolo.
///////////////////
Index: cp/call.c
===================================================================
--- cp/call.c (revision 212431)
+++ cp/call.c (working copy)
@@ -3773,9 +3773,13 @@ build_user_type_conversion_1 (tree totype, tree ex
if (flags & LOOKUP_NO_NARROWING)
conv->check_narrowing = true;
- /* Combine it with the second conversion sequence. */
- cand->second_conv = merge_conversion_sequences (conv,
- cand->second_conv);
+ if (!(flags & LOOKUP_FOR_CHECK_NARROWING))
+ /* Combine it with the second conversion sequence. */
+ cand->second_conv = merge_conversion_sequences (conv,
+ cand->second_conv);
+ else
+ /* For convert_for_check_narrowing drop the second conversion. */
+ cand->second_conv = conv;
return cand;
}
@@ -3809,6 +3813,37 @@ build_user_type_conversion (tree totype, tree expr
return ret;
}
+/* Used by check_narrowing. */
+
+tree
+convert_for_check_narrowing (tree totype, tree expr)
+{
+ struct z_candidate *cand;
+ tree ret;
+
+ bool subtime = timevar_cond_start (TV_OVERLOAD);
+ cand = build_user_type_conversion_1 (totype, expr,
+ LOOKUP_NORMAL
+ | LOOKUP_FOR_CHECK_NARROWING,
+ tf_none);
+
+ if (cand)
+ {
+ if (cand->second_conv->kind == ck_ambig)
+ ret = error_mark_node;
+ else
+ ret = convert_like (cand->second_conv, expr, tf_none);
+ }
+ else
+ ret = NULL_TREE;
+
+ if (!ret || ret == error_mark_node)
+ ret = expr;
+
+ timevar_cond_stop (TV_OVERLOAD, subtime);
+ return ret;
+}
+
/* Subroutine of convert_nontype_argument.
EXPR is an argument for a template non-type parameter of integral or
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h (revision 212431)
+++ cp/cp-tree.h (working copy)
@@ -4573,6 +4573,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, T
#define LOOKUP_NO_NON_INTEGRAL (LOOKUP_NO_RVAL_BIND << 1)
/* Used for delegating constructors in order to diagnose self-delegation. */
#define LOOKUP_DELEGATING_CONS (LOOKUP_NO_NON_INTEGRAL << 1)
+/* Used by convert_for_check_narrowing. */
+#define LOOKUP_FOR_CHECK_NARROWING (LOOKUP_DELEGATING_CONS << 1)
#define LOOKUP_NAMESPACES_ONLY(F) \
(((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
@@ -5050,6 +5052,8 @@ extern bool sufficient_parms_p
(const_tree);
extern tree type_decays_to (tree);
extern tree build_user_type_conversion (tree, tree, int,
tsubst_flags_t);
+extern tree convert_for_check_narrowing (tree, tree);
+
extern tree build_new_function_call (tree, vec<tree, va_gc> **,
bool,
tsubst_flags_t);
extern tree build_operator_new_call (tree, vec<tree, va_gc> **,
tree *,
Index: cp/typeck2.c
===================================================================
--- cp/typeck2.c (revision 212431)
+++ cp/typeck2.c (working copy)
@@ -854,6 +854,13 @@ check_narrowing (tree type, tree init)
if (!warn_narrowing || !ARITHMETIC_TYPE_P (type))
return;
+ if (CLASS_TYPE_P (ftype))
+ {
+ /* Look through, eg, conversion operators (c++/53159). */
+ init = convert_for_check_narrowing (type, init);
+ ftype = unlowered_expr_type (init);
+ }
+
if (BRACE_ENCLOSED_INITIALIZER_P (init)
&& TREE_CODE (type) == COMPLEX_TYPE)
{
Index: testsuite/g++.dg/cpp0x/Wnarrowing1.C
===================================================================
--- testsuite/g++.dg/cpp0x/Wnarrowing1.C (revision 0)
+++ testsuite/g++.dg/cpp0x/Wnarrowing1.C (working copy)
@@ -0,0 +1,14 @@
+// PR c++/53159
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wnarrowing -Wno-overflow" }
+
+struct X
+{
+ constexpr operator int() { return __INT_MAX__; }
+};
+
+int f() { return __INT_MAX__; }
+
+signed char a { __INT_MAX__ }; // { dg-warning "narrowing conversion" }
+signed char b { f() }; // { dg-warning "narrowing conversion" }
+signed char c { X{} }; // { dg-warning "narrowing conversion" }