re PR c++/49107 ([C++0x][4.7 Regression] incomplete type regression with std::pair)
authorJason Merrill <jason@redhat.com>
Wed, 15 Jun 2011 03:51:59 +0000 (23:51 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 15 Jun 2011 03:51:59 +0000 (23:51 -0400)
PR c++/49107
* cp-tree.h (DEFERRED_NOEXCEPT_SPEC_P): Handle overload.
* method.c (defaulted_late_check): Only maybe_instantiate_noexcept
if the declaration had an exception-specifier.
(process_subob_fn): Don't maybe_instantiate_noexcept.
* pt.c (maybe_instantiate_noexcept): Handle overload.
* typeck2.c (nothrow_spec_p_uninst): New.
(merge_exception_specifiers): Add 'fn' parm.  Build up overload.
* typeck.c (merge_types): Adjust.

From-SVN: r175073

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/method.c
gcc/cp/pt.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/noexcept13.C [new file with mode: 0644]

index 01a596fd06095064a7e0877444a9de063c8e2ab1..88bb8fb35a093bbcadd75694824b95fb8121ff0c 100644 (file)
@@ -1,5 +1,15 @@
 2011-06-14  Jason Merrill  <jason@redhat.com>
 
+       PR c++/49107
+       * cp-tree.h (DEFERRED_NOEXCEPT_SPEC_P): Handle overload.
+       * method.c (defaulted_late_check): Only maybe_instantiate_noexcept
+       if the declaration had an exception-specifier.
+       (process_subob_fn): Don't maybe_instantiate_noexcept.
+       * pt.c (maybe_instantiate_noexcept): Handle overload.
+       * typeck2.c (nothrow_spec_p_uninst): New.
+       (merge_exception_specifiers): Add 'fn' parm.  Build up overload.
+       * typeck.c (merge_types): Adjust.
+
        * pt.c (deduction_tsubst_fntype): Don't save input_location.
        (maybe_instantiate_noexcept): Likewise.
 
index 06b5926faa862cc490689d7e334b68e9f6f64889..ff8b2dc121ebe253c5b800b16f41f4a3ba673bb1 100644 (file)
@@ -514,7 +514,8 @@ struct GTY (()) tree_default_arg {
   (((struct tree_deferred_noexcept *)DEFERRED_NOEXCEPT_CHECK (NODE))->args)
 #define DEFERRED_NOEXCEPT_SPEC_P(NODE)                         \
   ((NODE) && (TREE_PURPOSE (NODE))                             \
-   && TREE_CODE (TREE_PURPOSE (NODE)) == DEFERRED_NOEXCEPT)
+  && (TREE_CODE (TREE_PURPOSE (NODE)) == DEFERRED_NOEXCEPT     \
+      || is_overloaded_fn (TREE_PURPOSE (NODE))))
 
 struct GTY (()) tree_deferred_noexcept {
   struct tree_base base;
@@ -1792,7 +1793,10 @@ struct GTY((variable_size)) lang_type {
    this type can raise.  Each TREE_VALUE is a _TYPE.  The TREE_VALUE
    will be NULL_TREE to indicate a throw specification of `()', or
    no exceptions allowed.  For a noexcept specification, TREE_VALUE
-   is NULL_TREE and TREE_PURPOSE is the constant-expression. */
+   is NULL_TREE and TREE_PURPOSE is the constant-expression.  For
+   a deferred noexcept-specification, TREE_PURPOSE is a DEFERRED_NOEXCEPT
+   (for templates) or an OVERLOAD list of functions (for implicitly
+   declared functions).  */
 #define TYPE_RAISES_EXCEPTIONS(NODE) TYPE_LANG_SLOT_1 (NODE)
 
 /* For FUNCTION_TYPE or METHOD_TYPE, return 1 iff it is declared `throw()'
@@ -5698,7 +5702,7 @@ extern tree build_x_arrow                 (tree);
 extern tree build_m_component_ref              (tree, tree);
 extern tree build_functional_cast              (tree, tree, tsubst_flags_t);
 extern tree add_exception_specifier            (tree, tree, int);
-extern tree merge_exception_specifiers         (tree, tree);
+extern tree merge_exception_specifiers         (tree, tree, tree);
 
 /* in mangle.c */
 extern void init_mangle                                (void);
index 06e20e271752973a119299201ab23126d7b017d4..48b9c74e78e5cf52cfb6428567806e7c14e30058 100644 (file)
@@ -924,10 +924,8 @@ process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
 
   if (spec_p)
     {
-      tree raises;
-      maybe_instantiate_noexcept (fn);
-      raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
-      *spec_p = merge_exception_specifiers (*spec_p, raises);
+      tree raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+      *spec_p = merge_exception_specifiers (*spec_p, raises, fn);
     }
 
   if (!trivial_fn_p (fn))
@@ -1561,15 +1559,16 @@ defaulted_late_check (tree fn)
      it had been implicitly declared.  */
   if (DECL_DEFAULTED_IN_CLASS_P (fn))
     {
-      tree eh_spec;
-      maybe_instantiate_noexcept (fn);
-      eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
-      if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))
-         && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)),
-                                eh_spec, ce_normal))
-       error ("function %q+D defaulted on its first declaration "
-              "with an exception-specification that differs from "
-              "the implicit declaration %q#D", fn, implicit_fn);
+      tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
+      if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
+       {
+         maybe_instantiate_noexcept (fn);
+         if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)),
+                                 eh_spec, ce_normal))
+           error ("function %q+D defaulted on its first declaration "
+                  "with an exception-specification that differs from "
+                  "the implicit declaration %q#D", fn, implicit_fn);
+       }
       TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
       if (DECL_DECLARED_CONSTEXPR_P (implicit_fn))
        /* Hmm...should we do this for out-of-class too? Should it be OK to
index 5f53ce88cfc0e8d623707c362702ed14778ecbd6..ff145a263fd397ce4c6e4f2628393cb025fcc11f 100644 (file)
@@ -17354,27 +17354,49 @@ always_instantiate_p (tree decl)
 void
 maybe_instantiate_noexcept (tree fn)
 {
-  tree fntype = TREE_TYPE (fn);
-  tree spec = TYPE_RAISES_EXCEPTIONS (fntype);
-  tree noex = NULL_TREE;
-  tree clone;
+  tree fntype, spec, noex, clone;
+
+  if (DECL_CLONED_FUNCTION_P (fn))
+    fn = DECL_CLONED_FUNCTION (fn);
+  fntype = TREE_TYPE (fn);
+  spec = TYPE_RAISES_EXCEPTIONS (fntype);
 
   if (!DEFERRED_NOEXCEPT_SPEC_P (spec))
     return;
+
   noex = TREE_PURPOSE (spec);
 
-  push_tinst_level (fn);
-  push_access_scope (fn);
-  input_location = DECL_SOURCE_LOCATION (fn);
-  noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
-                               DEFERRED_NOEXCEPT_ARGS (noex),
-                               tf_warning_or_error, fn, /*function_p=*/false,
-                               /*integral_constant_expression_p=*/true);
-  pop_access_scope (fn);
-  pop_tinst_level ();
-  spec = build_noexcept_spec (noex, tf_warning_or_error);
-  if (spec == error_mark_node)
-    spec = noexcept_false_spec;
+  if (TREE_CODE (noex) == DEFERRED_NOEXCEPT)
+    {
+      push_tinst_level (fn);
+      push_access_scope (fn);
+      input_location = DECL_SOURCE_LOCATION (fn);
+      noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
+                                   DEFERRED_NOEXCEPT_ARGS (noex),
+                                   tf_warning_or_error, fn, /*function_p=*/false,
+                                   /*integral_constant_expression_p=*/true);
+      pop_access_scope (fn);
+      pop_tinst_level ();
+      spec = build_noexcept_spec (noex, tf_warning_or_error);
+      if (spec == error_mark_node)
+       spec = noexcept_false_spec;
+    }
+  else
+    {
+      /* This is an implicitly declared function, so NOEX is a list of
+        other functions to evaluate and merge.  */
+      tree elt;
+      spec = noexcept_true_spec;
+      for (elt = noex; elt; elt = OVL_NEXT (elt))
+       {
+         tree fn = OVL_CURRENT (elt);
+         tree subspec;
+         maybe_instantiate_noexcept (fn);
+         subspec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+         spec = merge_exception_specifiers (spec, subspec, NULL_TREE);
+       }
+    }
+
   TREE_TYPE (fn) = build_exception_variant (fntype, spec);
 
   FOR_EACH_CLONE (clone, fn)
index 1bed291617e8900660f4199688f2b5ce85c2db26..39e974bb8027befe26b276a70e36d849774a1cb4 100644 (file)
@@ -830,7 +830,8 @@ merge_types (tree t1, tree t2)
        gcc_assert (type_memfn_quals (t1) == type_memfn_quals (t2));
        rval = apply_memfn_quals (rval, type_memfn_quals (t1));
        raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
-                                            TYPE_RAISES_EXCEPTIONS (t2));
+                                            TYPE_RAISES_EXCEPTIONS (t2),
+                                            NULL_TREE);
        t1 = build_exception_variant (rval, raises);
        break;
       }
@@ -841,7 +842,8 @@ merge_types (tree t1, tree t2)
           is just the main variant of this.  */
        tree basetype = class_of_this_parm (t2);
        tree raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
-                                                 TYPE_RAISES_EXCEPTIONS (t2));
+                                                 TYPE_RAISES_EXCEPTIONS (t2),
+                                                 NULL_TREE);
        tree t3;
 
        /* If this was a member function type, get back to the
index d72f57ec937acbcc00ba9bec5545cad12e148b6b..6d6267e8d728fa370fe505afc2a5cb41e5f99f0e 100644 (file)
@@ -1771,12 +1771,24 @@ add_exception_specifier (tree list, tree spec, int complain)
   return list;
 }
 
+/* Like nothrow_spec_p, but don't abort on deferred noexcept.  */
+
+static bool
+nothrow_spec_p_uninst (const_tree spec)
+{
+  if (DEFERRED_NOEXCEPT_SPEC_P (spec))
+    return false;
+  return nothrow_spec_p (spec);
+}
+
 /* Combine the two exceptions specifier lists LIST and ADD, and return
-   their union.  */
+   their union.  If FN is non-null, it's the source of ADD.  */
 
 tree
-merge_exception_specifiers (tree list, tree add)
+merge_exception_specifiers (tree list, tree add, tree fn)
 {
+  tree noex, orig_list;
+
   /* No exception-specifier or noexcept(false) are less strict than
      anything else.  Prefer the newer variant (LIST).  */
   if (!list || list == noexcept_false_spec)
@@ -1784,37 +1796,51 @@ merge_exception_specifiers (tree list, tree add)
   else if (!add || add == noexcept_false_spec)
     return add;
 
-  /* We need to instantiate deferred noexcept before we get here.  */
-  gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (list)
-             && !DEFERRED_NOEXCEPT_SPEC_P (add));
-
-  /* For merging noexcept(true) and throw(), take the more recent one (LIST).
-     Any other noexcept-spec should only be merged with an equivalent one.
-     So the !TREE_VALUE code below is correct for all cases.  */
-  if (!TREE_VALUE (add))
+  /* noexcept(true) and throw() are stricter than anything else.
+     As above, prefer the more recent one (LIST).  */
+  if (nothrow_spec_p_uninst (add))
     return list;
-  else if (!TREE_VALUE (list))
+
+  noex = TREE_PURPOSE (list);
+  if (DEFERRED_NOEXCEPT_SPEC_P (add))
+    {
+      /* If ADD is a deferred noexcept, we must have been called from
+        process_subob_fn.  For implicitly declared functions, we build up
+        a list of functions to consider at instantiation time.  */
+      if (noex == boolean_true_node)
+       noex = NULL_TREE;
+      gcc_assert (fn && (!noex || is_overloaded_fn (noex)));
+      noex = build_overload (fn, noex);
+    }
+  else if (nothrow_spec_p_uninst (list))
     return add;
   else
+    gcc_checking_assert (!TREE_PURPOSE (add)
+                        || cp_tree_equal (noex, TREE_PURPOSE (add)));
+
+  /* Combine the dynamic-exception-specifiers, if any.  */
+  orig_list = list;
+  for (; add && TREE_VALUE (add); add = TREE_CHAIN (add))
     {
-      tree orig_list = list;
+      tree spec = TREE_VALUE (add);
+      tree probe;
 
-      for (; add; add = TREE_CHAIN (add))
+      for (probe = orig_list; probe && TREE_VALUE (probe);
+          probe = TREE_CHAIN (probe))
+       if (same_type_p (TREE_VALUE (probe), spec))
+         break;
+      if (!probe)
        {
-         tree spec = TREE_VALUE (add);
-         tree probe;
-
-         for (probe = orig_list; probe; probe = TREE_CHAIN (probe))
-           if (same_type_p (TREE_VALUE (probe), spec))
-             break;
-         if (!probe)
-           {
-             spec = build_tree_list (NULL_TREE, spec);
-             TREE_CHAIN (spec) = list;
-             list = spec;
-           }
+         spec = build_tree_list (NULL_TREE, spec);
+         TREE_CHAIN (spec) = list;
+         list = spec;
        }
     }
+
+  /* Keep the noexcept-specifier at the beginning of the list.  */
+  if (noex != TREE_PURPOSE (list))
+    list = tree_cons (noex, TREE_VALUE (list), TREE_CHAIN (list));
+
   return list;
 }
 
index cecd85bc3f4b7915ba88693ac426a4b9063999c0..265f95daf716e23e6c9cfdb409806440ec7f1068 100644 (file)
@@ -1,3 +1,7 @@
+2011-06-14  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/cpp0x/noexcept13.C: New.
+
 2011-06-14  Easwaran Raman  <eraman@google.com>
 
        PR rtl-optimization/44194
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept13.C b/gcc/testsuite/g++.dg/cpp0x/noexcept13.C
new file mode 100644 (file)
index 0000000..7d51c82
--- /dev/null
@@ -0,0 +1,78 @@
+// PR c++/49107
+// { dg-options -std=c++0x }
+
+namespace std
+{
+  template<typename _Tp> _Tp&& declval() noexcept;
+
+  struct true_type { static const bool value = true; };
+  struct false_type { static const bool value = false; };
+
+  template<typename _Tp, typename _Arg>
+    struct __is_direct_constructible_impl
+    {
+      template<typename _Tp2, typename _Arg2, typename
+              = decltype(::new _Tp2(declval<_Arg2>()))>
+      static true_type __test(int);
+
+      template<typename, typename>
+      static false_type __test(...);
+
+      typedef decltype(__test<_Tp, _Arg>(0)) type;
+    };
+
+  template<typename _Tp, typename _Arg>
+    struct __is_direct_constructible_new_safe
+    : public __is_direct_constructible_impl<_Tp, _Arg>::type
+    { };
+
+  template<class _T1, class _T2>
+    struct pair
+    {
+      pair() = default;
+      constexpr pair(const pair&) = default;
+
+      pair(pair&& __p)
+      noexcept(__is_direct_constructible_new_safe<_T2,_T2&&>::value);
+    };
+}
+
+template <class R_>
+struct Vector3
+{
+  typedef typename R_::Ray_3 Ray_3;
+  Vector3() {}
+  explicit Vector3(const Ray_3& r);
+};
+
+template < class R_ > class LineC3
+{
+  typedef typename R_::Vector_3 Vector_3;
+  std::pair<int, Vector_3> x;
+};
+
+template < class R_ > class RayH3
+{
+  typedef typename R_::Vector_3 Vector_3;
+  std::pair<int, Vector_3> x;
+};
+
+template <typename Kernel >
+struct Homogeneous_base
+{
+  typedef LineC3<Kernel> Line_3;
+  typedef RayH3<Kernel> Ray_3;
+};
+
+template < typename RT_>
+struct Simple_homogeneous
+: public Homogeneous_base< Simple_homogeneous<RT_> >
+{
+  typedef Vector3<Simple_homogeneous<RT_> > Vector_3;
+};
+
+int main()
+{
+  typedef Simple_homogeneous<double> R;
+  R::Line_3 l3;
+}