gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/explicit15.C: New test.
* g++.dg/cpp1z/class-deduction108.C: New test.
---
gcc/cp/cp-tree.h | 1 +
gcc/cp/decl.cc | 3 +
gcc/cp/init.cc | 20 +++--
gcc/cp/pt.cc | 3 +-
gcc/testsuite/g++.dg/cpp0x/explicit15.C | 83 +++++++++++++++++++
.../g++.dg/cpp1z/class-deduction108.C | 78 +++++++++++++++++
6 files changed, 181 insertions(+), 7 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/explicit15.C
create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction108.C
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ac723901098..fd76909ca75 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7039,6 +7039,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 199ac768d43..5452f7d9cb3 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -7968,6 +7968,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..d5faa0dc519 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,20 @@ is_class_type (tree type, int or_else)
return 1;
}
+/* Returns true iff the variable 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 402365285cf..e8b5d8fbb73 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -26602,8 +26602,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..076d8b31631
--- /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<class T>
+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<class T>
+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<int>();
+template void g<A>();
+
+template<class T>
+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}; // { dg-bogus "cannot convert" }
+ static constexpr T t5 = T(a);
+ static constexpr T t6 = T{a};
+};
+
+template<class T>
+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}; // { dg-bogus "cannot convert" }
+ static constexpr int n5 = int(t);
+ static constexpr int n6 = int{t};
+};
+
+template struct B<int>;
+template struct C<A>;
+
+#if __cpp_inline_variables
+template<class T>
+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<class T>
+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<int>;
+template struct E<A>;
+#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<class T>
+struct A {
+ constexpr A() { }
+ constexpr A(int) { }
+};
+
+explicit A(...) -> A<int>;
+
+template<template<class> 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<class T>
+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<A>();
+template void g(int);
+
+template<template<class> 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<class T>
+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<A>;
+template struct C<int>;
+
+template<template<class> 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<class T>
+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<A>;
+template struct F<int>;