diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/class.cc | 25 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/method.cc | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/is_constructible3.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/is_constructible7.C | 28 |
5 files changed, 75 insertions, 5 deletions
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index 40e1714..c75b889 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -5415,10 +5415,11 @@ type_has_user_provided_or_explicit_constructor (tree t) /* Returns true iff class T has a non-user-provided (i.e. implicitly declared or explicitly defaulted in the class body) default - constructor. */ + constructor. If SYNTH, only return true if it hasn't been + implicitly defined yet. */ -bool -type_has_non_user_provided_default_constructor (tree t) +static bool +type_has_non_user_provided_default_constructor_1 (tree t, bool synth) { if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (t)) return false; @@ -5431,12 +5432,28 @@ type_has_non_user_provided_default_constructor (tree t) if (TREE_CODE (fn) == FUNCTION_DECL && default_ctor_p (fn) && !user_provided_p (fn)) - return true; + { + if (synth) + return !DECL_INITIAL (fn); + return true; + } } return false; } +bool +type_has_non_user_provided_default_constructor (tree t) +{ + return type_has_non_user_provided_default_constructor_1 (t, false); +} + +bool +type_has_default_ctor_to_be_synthesized (tree t) +{ + return type_has_non_user_provided_default_constructor_1 (t, true); +} + /* TYPE is being used as a virtual base, and has a non-trivial move assignment. Return true if this is due to there being a user-provided move assignment in TYPE or one of its subobjects; if there isn't, then diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2f71885..02734a4 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6720,6 +6720,7 @@ extern tree in_class_defaulted_default_constructor (tree); extern bool user_provided_p (tree); extern bool type_has_user_provided_constructor (tree); extern bool type_has_non_user_provided_default_constructor (tree); +extern bool type_has_default_ctor_to_be_synthesized (tree); extern bool vbase_has_user_provided_move_assign (tree); extern tree default_init_uninitialized_part (tree); extern bool trivial_default_constructor_is_constexpr (tree); diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 903ee66..e0fe217 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -2056,6 +2056,28 @@ assignable_expr (tree to, tree from) return r; } +/* An unparsed default member initializer prevents calling a defaulted default + constructor; make checking std::is_constructible ill-formed until the DMI + has been parsed, to avoid caching the wrong value. */ + +static bool +complain_about_unparsed_dmi (tree t) +{ + if (type_has_default_ctor_to_be_synthesized (t) + && TYPE_HAS_COMPLEX_DFLT (t)) + for (tree f = TYPE_FIELDS (t); f; f = DECL_CHAIN (f)) + if (TREE_CODE (f) == FIELD_DECL + && DECL_INITIAL (f) + && TREE_CODE (DECL_INITIAL (f)) == DEFERRED_PARSE) + { + error ("default member initializer for %qD required by %qs before " + "the end of its enclosing class", f, "std::is_constructible"); + inform (location_of (f), "defined here"); + return true; + } + return false; +} + /* The predicate condition for a template specialization is_constructible<T, Args...> shall be satisfied if and only if the following variable definition would be well-formed for some invented @@ -2070,6 +2092,8 @@ constructible_expr (tree to, tree from) cp_unevaluated cp_uneval_guard; if (CLASS_TYPE_P (to)) { + if (!from && complain_about_unparsed_dmi (to)) + return error_mark_node; tree ctype = to; vec<tree, va_gc> *args = NULL; if (!TYPE_REF_P (to)) diff --git a/gcc/testsuite/g++.dg/ext/is_constructible3.C b/gcc/testsuite/g++.dg/ext/is_constructible3.C index c7c5874..305751d 100644 --- a/gcc/testsuite/g++.dg/ext/is_constructible3.C +++ b/gcc/testsuite/g++.dg/ext/is_constructible3.C @@ -8,7 +8,7 @@ struct A { B() = default; }; - static constexpr bool v = __is_constructible (B); + static constexpr bool v = __is_constructible (B); // { dg-error "member initializer" } }; diff --git a/gcc/testsuite/g++.dg/ext/is_constructible7.C b/gcc/testsuite/g++.dg/ext/is_constructible7.C new file mode 100644 index 0000000..76a63bb --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_constructible7.C @@ -0,0 +1,28 @@ +// PR c++/96645 +// { dg-do compile { target c++11 } } + +template<bool B> +struct bool_constant +{ + static constexpr bool value = B; + using type = bool_constant; +}; + +using true_type = bool_constant<true>; + +template<typename T> +struct is_default_constructible + : bool_constant<__is_constructible(T)> // { dg-error "default member init" } +{ }; + +void testVarStruct() +{ + struct DataWithStruct { + struct A { + int number = 5; // compiles, if remove initialization + }; + + // { dg-prune-output "could not convert" } + is_default_constructible<A>::type t = true_type{}; + }; +} |