public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-7804] c++: delayed parse DMI [PR96645]
@ 2022-03-24 18:31 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2022-03-24 18:31 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:346ab5a54a831ad9c78afcbd8dfe98e0e07e3070

commit r12-7804-g346ab5a54a831ad9c78afcbd8dfe98e0e07e3070
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Mar 22 01:10:44 2022 -0400

    c++: delayed parse DMI [PR96645]
    
    With the changes for PR81359 and PR88368 to make get_nsdmi errors be treated
    as substitution failure, we have the problem that if we check
    std::is_default_constructible for a complete class that still has unparsed
    default member initializers, we get an answer (false) that will be wrong
    once the DMIs have been parsed.  The traits avoid this problem for regular
    incomplete classes by giving an error if the operand is incomplete; we
    should do the same if get_nsdmi is going to fail due to unparsed DMI.
    
            PR c++/96645
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (type_has_default_ctor_to_be_synthesized): Declare.
            * class.cc (type_has_default_ctor_to_be_synthesized): New.
            (type_has_non_user_provided_default_constructor_1): Support it.
            (type_has_non_user_provided_default_constructor): Now a wrapper.
            * method.cc (complain_about_unparsed_dmi): New.
            (constructible_expr): Call it.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/ext/is_constructible3.C: Expect error.
            * g++.dg/ext/is_constructible7.C: New test.

Diff:
---
 gcc/cp/cp-tree.h                             |  1 +
 gcc/cp/class.cc                              | 25 +++++++++++++++++++++----
 gcc/cp/method.cc                             | 24 ++++++++++++++++++++++++
 gcc/testsuite/g++.dg/ext/is_constructible3.C |  2 +-
 gcc/testsuite/g++.dg/ext/is_constructible7.C | 28 ++++++++++++++++++++++++++++
 5 files changed, 75 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2f718852ac1..02734a42f1b 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/class.cc b/gcc/cp/class.cc
index 40e17140db5..c75b889cb84 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/method.cc b/gcc/cp/method.cc
index 903ee666ef3..e0fe2177730 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 c7c58746cd0..305751d28e2 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 00000000000..76a63bba5d0
--- /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{};
+  };
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-03-24 18:31 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-24 18:31 [gcc r12-7804] c++: delayed parse DMI [PR96645] Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).