This patch from Le-Chun Wu distinguishes explicit from implicit template arguments to avoid emitting NULL warnings for implicit arguments.
Additionally, Le-Chun extended the pointer to boolean conversion warnings to also warn when assigning a boolean value to a pointer. Le-Chun, if I'm missing anything, please correct me. Jason, OK for trunk? Applied to google/main. 2011-04-27 Le-Chun Wu <l...@google.com> Google ref 40484. * cp-tree.h (LOOKUP_EXPLICIT_TMPL_ARGS): Define. * call.c (build_new_function_call): Set it for TEMPLATE_ID_EXPRs. (build_over_call): Use it to determine whether to emit a NULL warning for template function instantiations. (build_new_method_call): Set LOOKUP_EXPLICIT_TMPL_ARGS if EXPLICIT_TARGS is set. testsuite/ChangeLog.google-main 2011-04-27 Le-Chun Wu <l...@google.com> * g++.dg/warn/Wnull-conversion-1.C: New. * g++.dg/warn/Wnull-conversion-2.C: New. cp/ChangeLog.google-main 2011-04-28 Diego Novillo <dnovi...@google.com> Le-Chun Wu <l...@google.com> * call.c (conversion_null_warnings): Also handle assignments when warning about NULL conversions. testsuite/ChangeLog.google-main 2011-04-28 Le-Chun Wu <l...@google.com> * g++.dg/warn/Wconversion-null-2.C: Do not expect a NULL warning in implicitly instantiated templates. 2011-04-29 Diego Novillo <dnovi...@google.com> * g++.old-deja/g++.other/null3.C: Expect warning about converting boolean to a pointer. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 32aa5ca..f56a67d 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -3624,7 +3624,16 @@ build_new_function_call (tree fn, VEC(tree,gc) **args, bool koenig_p, result = error_mark_node; } else - result = build_over_call (cand, LOOKUP_NORMAL, complain); + { + int flags = LOOKUP_NORMAL; + /* If fn is template_id_expr, the call has explicit template arguments + (e.g. func<int>(5)), communicate this info to build_over_call + through flags so that later we can use it to decide whether to warn + about peculiar null pointer conversion. */ + if (TREE_CODE (fn) == TEMPLATE_ID_EXPR) + flags |= LOOKUP_EXPLICIT_TMPL_ARGS; + result = build_over_call (cand, flags, complain); + } /* Free all the conversions we allocated. */ obstack_free (&conversion_obstack, p); @@ -5264,10 +5273,16 @@ conversion_null_warnings (tree totype, tree expr, tree fn, int argnum) } /* Issue warnings if "false" is converted to a NULL pointer */ - else if (expr == boolean_false_node && fn && POINTER_TYPE_P (t)) - warning_at (input_location, OPT_Wconversion_null, - "converting %<false%> to pointer type for argument %P of %qD", - argnum, fn); + else if (expr == boolean_false_node && POINTER_TYPE_P (t)) + { + if (fn) + warning_at (input_location, OPT_Wconversion_null, + "converting %<false%> to pointer type for argument %P " + "of %qD", argnum, fn); + else + warning_at (input_location, OPT_Wconversion_null, + "converting %<false%> to pointer type %qT", t); + } } /* Perform the conversions in CONVS on the expression EXPR. FN and @@ -6163,6 +6178,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) { tree type = TREE_VALUE (parm); tree arg = VEC_index (tree, args, arg_index); + bool conversion_warning = true; conv = convs[i]; @@ -6172,6 +6188,32 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) && !TREE_ADDRESSABLE (type)) conv = conv->u.next; + /* If the argument is NULL and used to (implicitly) instantiate a + template function (and bind one of the template arguments to + the type of 'long int'), we don't want to warn about passing NULL + to non-pointer argument. + For example, if we have this template function: + + template<typename T> void func(T x) {} + + we want to warn (when -Wconversion is enabled) in this case: + + void foo() { + func<int>(NULL); + } + + but not in this case: + + void foo() { + func(NULL); + } + */ + if (arg == null_node + && DECL_TEMPLATE_INFO (fn) + && cand->template_decl + && !(flags & LOOKUP_EXPLICIT_TMPL_ARGS)) + conversion_warning = false; + /* Warn about initializer_list deduction that isn't currently in the working draft. */ if (cxx_dialect > cxx98 @@ -6202,7 +6244,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) } } - val = convert_like_with_context (conv, arg, fn, i-is_method, complain); + val = convert_like_with_context (conv, arg, fn, i-is_method, + conversion_warning + ? complain + : complain & (~tf_warning)); val = convert_for_arg_passing (type, val); if (val == error_mark_node) @@ -6983,6 +7028,8 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args, if (DECL_VINDEX (fn) && ! (flags & LOOKUP_NONVIRTUAL) && resolves_to_fixed_type_p (instance, 0)) flags |= LOOKUP_NONVIRTUAL; + if (explicit_targs) + flags |= LOOKUP_EXPLICIT_TMPL_ARGS; /* Now we know what function is being called. */ if (fn_p) *fn_p = fn; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b6efe94..e1aead7 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4230,6 +4230,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; /* Used in calls to store_init_value to suppress its usual call to digest_init. */ #define LOOKUP_ALREADY_DIGESTED (LOOKUP_DEFAULTED << 1) +/* An instantiation with explicit template arguments. */ +#define LOOKUP_EXPLICIT_TMPL_ARGS (LOOKUP_ALREADY_DIGESTED << 1) #define LOOKUP_NAMESPACES_ONLY(F) \ (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES)) diff --git a/gcc/testsuite/g++.dg/warn/Wconversion-null-2.C b/gcc/testsuite/g++.dg/warn/Wconversion-null-2.C index c3050f6..dd498c1 100644 --- a/gcc/testsuite/g++.dg/warn/Wconversion-null-2.C +++ b/gcc/testsuite/g++.dg/warn/Wconversion-null-2.C @@ -44,6 +44,6 @@ int main() k(NULL); // { dg-warning "" } converting NULL to int g(NULL); // { dg-warning "" } converting NULL to int h<NULL>(); // No warning: NULL bound to integer template parameter - l(NULL); // { dg-warning "" } converting NULL to int + l(NULL); // No warning: NULL is used to implicitly instantiate the template NULL && NULL; // No warning: converting NULL to bool is OK } diff --git a/gcc/testsuite/g++.dg/warn/Wnull-conversion-1.C b/gcc/testsuite/g++.dg/warn/Wnull-conversion-1.C new file mode 100644 index 0000000..511f091 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wnull-conversion-1.C @@ -0,0 +1,15 @@ +// { dg-do compile } +// { dg-options "-Wconversion-null" } + +#include <stddef.h> + +void func1(int* ptr); + +void func2() { + int* t = false; // { dg-warning "converting 'false' to pointer" } + int* p; + p = false; // { dg-warning "converting 'false' to pointer" } + int* r = sizeof(char) / 2; + func1(false); // { dg-warning "converting 'false' to pointer" } + int i = NULL; // { dg-warning "converting to non-pointer" } +} diff --git a/gcc/testsuite/g++.dg/warn/Wnull-conversion-2.C b/gcc/testsuite/g++.dg/warn/Wnull-conversion-2.C new file mode 100644 index 0000000..92a87d1 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wnull-conversion-2.C @@ -0,0 +1,45 @@ +// { dg-do compile } +// { dg-options "-Wconversion-null" } + +#include <stddef.h> + +class Foo { + public: + template <typename T1, typename T2> + static void Compare(const T1& expected, const T2& actual) { } + + template <typename T1, typename T2> + static void Compare(const T1& expected, T2* actual) { } + +}; + +template<typename T1> +class Foo2 { + public: + Foo2(int x); + template<typename T2> void Bar(T2 y); +}; + +template<typename T3> void func(T3 x) { } + +typedef Foo2<int> MyFooType; + +void func1(long int a) { + MyFooType *foo2 = new MyFooType(NULL); // { dg-warning "passing NULL to" } + foo2->Bar(a); + func(NULL); + func<int>(NULL); // { dg-warning "passing NULL to" } + func<int *>(NULL); +} + +int x = 1; + +main() +{ + int *p = &x; + + Foo::Compare(0, *p); + Foo::Compare<long int, int>(NULL, p); // { dg-warning "passing NULL to" } + Foo::Compare(NULL, p); + func1(NULL); // { dg-warning "passing NULL to" } +} diff --git a/gcc/testsuite/g++.old-deja/g++.other/null3.C b/gcc/testsuite/g++.old-deja/g++.other/null3.C index 6228caa..01071f9 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/null3.C +++ b/gcc/testsuite/g++.old-deja/g++.other/null3.C @@ -2,5 +2,5 @@ void x() { - int* p = 1==0; + int* p = 1==0; // { dg-warning "converting 'false' to pointer" } } -- 1.7.3.1 -- This patch is available for review at http://codereview.appspot.com/4436067