diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index c08bd0c8634a9722d39ce0cd240f368d0acb8d61..e440d58141baab29920cad55dd1a7f7bec06432e 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -3272,7 +3272,8 @@ add_builtin_candidate (struct z_candidate **candidates, enum tree_code code, break; /* Otherwise, the types should be pointers. */ - if (!TYPE_PTR_OR_PTRMEM_P (type1) || !TYPE_PTR_OR_PTRMEM_P (type2)) + if (!((TYPE_PTR_OR_PTRMEM_P (type1) || null_ptr_cst_p (args[0])) + && (TYPE_PTR_OR_PTRMEM_P (type2) || null_ptr_cst_p (args[1])))) return; /* We don't check that the two types are the same; the logic diff --git a/gcc/testsuite/g++.dg/conversion/op8.C b/gcc/testsuite/g++.dg/conversion/op8.C new file mode 100644 index 0000000000000000000000000000000000000000..eac958776c9444ed4bc354245c9a0acd86a05acf --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/op8.C @@ -0,0 +1,75 @@ +// PR c++/118282 +// { dg-do "compile" } + +#if __cplusplus >= 201103L +# include <cstdint> // Only available from c++11 onwards. +#endif + +struct A { + explicit A (int); + operator void* () const; +}; + +struct B { + explicit B (int); + operator char* () const; +}; + +struct C { + explicit C (int); + operator int () const; +}; + +struct BothWays { + BothWays (int); + operator void*() const; +}; + +extern bool my_bool; + +void foo (const A& a, const B& b, const C& c, const BothWays& d) { + void *res_a_1 = 0 ? 0 : a; + void *res_a_2 = 1 ? 0 : a; + void *res_a_3 = my_bool ? 0 : a; + void *res_a_4 = 0 ? a : 0; + void *res_a_5 = 1 ? a : 0; + void *res_a_6 = my_bool ? a : 0; + + void *res_b_1 = 0 ? 0 : b; + void *res_b_2 = 1 ? 0 : b; + void *res_b_3 = my_bool ? 0 : b; + void *res_b_4 = 0 ? b : 0; + void *res_b_5 = 1 ? b : 0; + void *res_b_6 = my_bool ? b : 0; + + // + // 0 valued constants that are NOT null pointer constants - this worked already. + // + char zero_char = 0; + void *res_ko1 = 0 ? zero_char : a; // { dg-error "different types" } + +#if __cplusplus >= 201103L + // Those are only available starting with c++11. + int8_t zero_i8 = 0; + void *res_ko2 = 0 ? zero_i8 : a; // { dg-error "different types" "" { target c++11 } } + uintptr_t zerop = 0; + void *res_ko3 = 0 ? zerop : a; // { dg-error "different types" "" { target c++11 } } +#endif + + // Conversion to integer - this worked already. + int res_int = 0 ? 0 : c; + + // Case where one arm is of class type that can be constructed from an + // integer and the other arm is a null pointer constant (inspired by + // g++.dg/template/cond5.C). + 0 ? d : 0; + 0 ? 0 : d; +} + +int main(){ + A a (5); + B b (42); + C c (43); + BothWays d (1982); + foo (a, b, c, d); +}