diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 757711bc03a..b71bce1ab97 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7037,6 +7037,7 @@ extern void emit_mem_initializers (tree); extern tree build_aggr_init (tree, tree, int, tsubst_flags_t); extern int is_class_type (tree, int); +extern bool is_copy_initialization (tree); extern tree build_zero_init (tree, tree, bool); extern tree build_value_init (tree, tsubst_flags_t); extern tree build_value_init_noctor (tree, tsubst_flags_t); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 48763c44518..992e38385c2 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -7962,6 +7962,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, if (type == error_mark_node) return; + if (VAR_P (decl) && is_copy_initialization (init)) + flags |= LOOKUP_ONLYCONVERTING; + /* Warn about register storage specifiers except when in GNU global or local register variable extension. */ if (VAR_P (decl) && DECL_REGISTER (decl) && asmspec_tree == NULL_TREE) diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index 545d904c0f9..cd1d6f82802 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -2019,11 +2019,7 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain) return stmt_expr; } - if (init && init != void_type_node - && TREE_CODE (init) != TREE_LIST - && !(TREE_CODE (init) == TARGET_EXPR - && TARGET_EXPR_DIRECT_INIT_P (init)) - && !DIRECT_LIST_INIT_P (init)) + if (is_copy_initialization (init)) flags |= LOOKUP_ONLYCONVERTING; is_global = begin_init_stmts (&stmt_expr, &compound_stmt); @@ -2331,6 +2327,19 @@ is_class_type (tree type, int or_else) return 1; } +/* Returns true iff the initializer INIT represents copy-initialization + (and therefore we must set LOOKUP_ONLYCONVERTING when processing it). */ + +bool +is_copy_initialization (tree init) +{ + return (init && init != void_type_node + && TREE_CODE (init) != TREE_LIST + && !(TREE_CODE (init) == TARGET_EXPR + && TARGET_EXPR_DIRECT_INIT_P (init)) + && !DIRECT_LIST_INIT_P (init)); +} + /* Build a reference to a member of an aggregate. This is not a C++ `&', but really something which can have its address taken, and then act as a pointer to member, for example TYPE :: FIELD can have diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index c93676ed8d2..f8069b2ea0e 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -26581,8 +26581,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) const_init = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern); cp_finish_decl (d, init, /*init_const_expr_p=*/const_init, - /*asmspec_tree=*/NULL_TREE, - LOOKUP_ONLYCONVERTING); + /*asmspec_tree=*/NULL_TREE, 0); } if (enter_context) pop_nested_class (); diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit15.C b/gcc/testsuite/g++.dg/cpp0x/explicit15.C new file mode 100644 index 00000000000..58ce97b2ad9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/explicit15.C @@ -0,0 +1,83 @@ +// PR c++/87820 +// { dg-do compile { target c++11 } } + +struct A { + constexpr explicit operator int() const { return 0; } +}; + +template +void f() { + A a; + T t1 = a; // { dg-error "cannot convert" } + T t2 = {a}; // { dg-error "cannot convert" } + T t3(a); + T t4{a}; + T t5 = T(a); + T t6 = T{a}; + new T(a); + new T{a}; +} + +template +void g() { + T t; + int n1 = t; // { dg-error "cannot convert" } + int n2 = {t}; // { dg-error "cannot convert" } + int n3(t); + int n4{t}; + int n5 = int(t); + int n6 = int{t}; + new int(t); + new int{t}; +} + +template void f(); +template void g(); + +template +struct B { + static constexpr A a{}; + static constexpr T t1 = a; // { dg-error "cannot convert" } + static constexpr T t2 = {a}; // { dg-error "cannot convert" } + static constexpr T t4{a}; + static constexpr T t5 = T(a); + static constexpr T t6 = T{a}; +}; + +template +struct C { + static constexpr T t{}; + static constexpr int n1 = t; // { dg-error "cannot convert" } + static constexpr int n2 = {t}; // { dg-error "cannot convert" } + static constexpr int n4{t}; + static constexpr int n5 = int(t); + static constexpr int n6 = int{t}; +}; + +template struct B; +template struct C; + +#if __cpp_inline_variables +template +struct D { + static inline A a; + static inline T t1 = a; // { dg-error "cannot convert" "" { target c++17 } } + static inline T t2 = {a}; // { dg-error "cannot convert" "" { target c++17 } } + static inline T t4{a}; + static inline T t5 = T(a); + static inline T t6 = T{a}; +}; + +template +struct E { + static inline T t; + static inline int n1 = t; // { dg-error "cannot convert" "" { target c++17 } } + static inline int n2 = {t}; // { dg-error "cannot convert" "" { target c++17 } } + static inline int n4{t}; + static inline int n5 = int(t); + static inline int n6 = int{t}; +}; + +template struct D; +template struct E; +#endif diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction108.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction108.C new file mode 100644 index 00000000000..e82c4bafb04 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction108.C @@ -0,0 +1,78 @@ +// PR c++/102137 +// { dg-do compile { target c++17 } } + +template +struct A { + constexpr A() { } + constexpr A(int) { } +}; + +explicit A(...) -> A; + +template class TT> +void f() { + TT x1 = 0; // { dg-error "deduction|no match" } + TT x2 = {0}; // { dg-error "explicit deduction guide" } + TT x3(0); + TT x4{0}; + TT x5; + new TT(0); + new TT{0}; + new TT(); + new TT{}; + new TT; +} + +template +void g(T t) { + A a1 = t; // { dg-error "deduction|no match" } + A a2 = {t}; // { dg-error "explicit deduction guide" } + A a3(t); + A a4{t}; + A a5; + new A(t); + new A{t}; +} + +template void f(); +template void g(int); + +template class TT> +struct B { + static inline TT x1 = 0; // { dg-error "deduction|no match" } + static inline TT x2 = {0}; // { dg-error "explicit deduction guide" } + static inline TT x4{0}; + static inline TT x5; +}; + +template +struct C { + static inline T t; + static inline A a1 = t; // { dg-error "deduction|no match" } + static inline A a2 = {t}; // { dg-error "explicit deduction guide" } + static inline A a4{t}; + static inline A a5{}; +}; + +template struct B; +template struct C; + +template class TT> +struct E { + static constexpr TT x1 = 0; // { dg-error "deduction|no match" } + static constexpr TT x2 = {0}; // { dg-error "explicit deduction guide" } + static constexpr TT x4{0}; + static constexpr TT x5{}; +}; + +template +struct F { + static constexpr T t{}; + static constexpr A a1 = t; // { dg-error "deduction|no match" } + static constexpr A a2 = {t}; // { dg-error "explicit deduction guide" } + static constexpr A a4{t}; + static constexpr A a5{}; +}; + +template struct E; +template struct F;