[gcc r11-5036] c++: Check abstract type only on object creation. [PR86252]

Jason Merrill jason@gcc.gnu.org
Sun Nov 15 17:08:51 GMT 2020


https://gcc.gnu.org/g:baf38d2e363971ed8baa5f82b2eaf21cd8e74aae

commit r11-5036-gbaf38d2e363971ed8baa5f82b2eaf21cd8e74aae
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Nov 13 16:33:50 2020 -0500

    c++: Check abstract type only on object creation. [PR86252]
    
    Abstract checking has been problematic for a while; when I implemented an
    earlier issue resolution to do more checking it led to undesirable
    instantiations, and so backed some of it out.  During the C++20 process we
    decided with P0929R2 that we should go the other way, and only check
    abstractness when we're actually creating an object, not when merely forming
    an array or function type.  This means that we can remove the machinery for
    checking whether a newly complete class makes some earlier declaration
    ill-formed.  This change was moved as a DR, so I'm applying it to all
    standard levels.  This could be reconsidered if it causes problems, but I
    don't expect it to.
    
    The change to the libstdc++ result_of test brings the expected behavior in
    line with that for incomplete types, but as in PR97841 I think the libstdc++
    handling of incomplete types in this and other type_traits is itself wrong,
    so I expect these lines and others to change again before long.
    
    gcc/cp/ChangeLog:
    
            * decl.c (cp_finish_decl): Only check abstractness on definition.
            (require_complete_types_for_parms): Check abstractness here.
            (create_array_type_for_decl): Not here.
            (grokdeclarator, grokparms, complete_vars): Not here.
            * pt.c (tsubst, tsubst_arg_types, tsubst_function_type): Not here.
            * typeck2.c (struct pending_abstract_type): Remove.
            (struct abstract_type_hasher): Remove.
            (abstract_pending_vars, complete_type_check_abstract): Remove.
            (abstract_virtuals_error_sfinae): Handle arrays.
            * call.c (conv_is_prvalue): Split out from...
            (conv_binds_ref_to_prvalue): ...here.
            (implicit_conversion_1): Rename from implicit_conversion.
            (implicit_conversion): An abstract prvalue is bad.
            (convert_like_internal): Don't complain if expr is already
            error_mark_node.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/other/abstract1.C: Adjust.
            * g++.dg/other/abstract2.C: Adjust.
            * g++.dg/other/abstract4.C: Adjust.
            * g++.dg/other/abstract5.C: Adjust.
            * g++.dg/other/abstract8.C: New test.
            * g++.dg/template/sfinae-dr657.C: Adjust.
            * g++.old-deja/g++.other/decl3.C: Adjust.
    
    libstdc++-v3/ChangeLog:
    
            * testsuite/20_util/result_of/sfinae_friendly_1.cc: Adjust.

Diff:
---
 gcc/cp/call.c                                      |  59 +++++---
 gcc/cp/decl.c                                      |  24 +---
 gcc/cp/pt.c                                        |   9 --
 gcc/cp/typeck2.c                                   | 159 +--------------------
 gcc/testsuite/g++.dg/other/abstract1.C             |  29 ++--
 gcc/testsuite/g++.dg/other/abstract2.C             |  57 ++++----
 gcc/testsuite/g++.dg/other/abstract4.C             |   4 +-
 gcc/testsuite/g++.dg/other/abstract5.C             |   2 +-
 gcc/testsuite/g++.dg/other/abstract8.C             |  40 ++++++
 gcc/testsuite/g++.dg/template/sfinae-dr657.C       |   9 +-
 gcc/testsuite/g++.old-deja/g++.other/decl3.C       |   2 +-
 .../20_util/result_of/sfinae_friendly_1.cc         |  10 +-
 12 files changed, 156 insertions(+), 248 deletions(-)

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 9861be1f856..3a6ad1332a7 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -213,6 +213,7 @@ static conversion *merge_conversion_sequences (conversion *, conversion *);
 static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t);
 static conversion *build_identity_conv (tree, tree);
 static inline bool conv_binds_to_array_of_unknown_bound (conversion *);
+static bool conv_is_prvalue (conversion *);
 static tree prevent_lifetime_extension (tree);
 
 /* Returns nonzero iff the destructor name specified in NAME matches BASETYPE.
@@ -1963,14 +1964,12 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
   return conv;
 }
 
-/* Returns the implicit conversion sequence (see [over.ics]) from type
-   FROM to type TO.  The optional expression EXPR may affect the
-   conversion.  FLAGS are the usual overloading flags.  If C_CAST_P is
-   true, this conversion is coming from a C-style cast.  */
+/* Most of the implementation of implicit_conversion, with the same
+   parameters.  */
 
 static conversion *
-implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
-		     int flags, tsubst_flags_t complain)
+implicit_conversion_1 (tree to, tree from, tree expr, bool c_cast_p,
+		       int flags, tsubst_flags_t complain)
 {
   conversion *conv;
 
@@ -2096,6 +2095,26 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
   return NULL;
 }
 
+/* Returns the implicit conversion sequence (see [over.ics]) from type
+   FROM to type TO.  The optional expression EXPR may affect the
+   conversion.  FLAGS are the usual overloading flags.  If C_CAST_P is
+   true, this conversion is coming from a C-style cast.  */
+
+static conversion *
+implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
+		     int flags, tsubst_flags_t complain)
+{
+  conversion *conv = implicit_conversion_1 (to, from, expr, c_cast_p,
+					    flags, complain);
+  if (!conv || conv->bad_p)
+    return conv;
+  if (conv_is_prvalue (conv)
+      && CLASS_TYPE_P (conv->type)
+      && CLASSTYPE_PURE_VIRTUALS (conv->type))
+    conv->bad_p = true;
+  return conv;
+}
+
 /* Like implicit_conversion, but return NULL if the conversion is bad.
 
    This is not static so that check_non_deducible_conversion can call it within
@@ -7407,7 +7426,7 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
 	  else if (t->kind == ck_identity)
 	    break;
 	}
-      if (!complained)
+      if (!complained && expr != error_mark_node)
 	{
 	  range_label_for_type_mismatch label (TREE_TYPE (expr), totype);
 	  gcc_rich_location richloc (loc, &label);
@@ -8438,20 +8457,15 @@ unsafe_copy_elision_p (tree target, tree exp)
 	  && !AGGR_INIT_VIA_CTOR_P (init));
 }
 
-/* True iff C is a conversion that binds a reference to a prvalue.  */
+/* True IFF the result of the conversion C is a prvalue.  */
 
 static bool
-conv_binds_ref_to_prvalue (conversion *c)
+conv_is_prvalue (conversion *c)
 {
-  if (c->kind != ck_ref_bind)
-    return false;
-  if (c->need_temporary_p)
-    return true;
-
-  c = next_conversion (c);
-
   if (c->kind == ck_rvalue)
     return true;
+  if (c->kind == ck_base && c->need_temporary_p)
+    return true;
   if (c->kind == ck_user && !TYPE_REF_P (c->type))
     return true;
   if (c->kind == ck_identity && c->u.expr
@@ -8461,6 +8475,19 @@ conv_binds_ref_to_prvalue (conversion *c)
   return false;
 }
 
+/* True iff C is a conversion that binds a reference to a prvalue.  */
+
+static bool
+conv_binds_ref_to_prvalue (conversion *c)
+{
+  if (c->kind != ck_ref_bind)
+    return false;
+  if (c->need_temporary_p)
+    return true;
+
+  return conv_is_prvalue (next_conversion (c));
+}
+
 /* True iff converting EXPR to a reference type TYPE does not involve
    creating a temporary.  */
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index c52111e329c..89bae06cd6b 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -7926,10 +7926,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 
       make_rtl_for_nonlocal_decl (decl, init, asmspec);
 
-      /* Check for abstractness of the type. Notice that there is no
-	 need to strip array types here since the check for those types
-	 is already done within create_array_type_for_decl.  */
-      abstract_virtuals_error (decl, type);
+      /* Check for abstractness of the type.  */
+      if (var_definition_p)
+	abstract_virtuals_error (decl, type);
 
       if (TREE_TYPE (decl) == error_mark_node)
 	/* No initialization required.  */
@@ -10701,11 +10700,6 @@ create_array_type_for_decl (tree name, tree type, tree size, location_t loc)
     itype = compute_array_index_type_loc (loc, name, size,
 					  tf_warning_or_error);
 
-  /* [dcl.array]
-     T is called the array element type; this type shall not be [...] an
-     abstract class type.  */
-  abstract_virtuals_error (name, type);
-
   return build_cplus_array_type (type, itype);
 }
 
@@ -12097,11 +12091,6 @@ grokdeclarator (const cp_declarator *declarator,
 
 	    /* Declaring a function type.  */
 
-	    {
-	      iloc_sentinel ils (declspecs->locations[ds_type_spec]);
-	      abstract_virtuals_error (ACU_RETURN, type);
-	    }
-
 	    /* Pick up type qualifiers which should be applied to `this'.  */
 	    memfn_quals = declarator->u.function.qualifiers;
 	    /* Pick up virt-specifiers.  */
@@ -13872,6 +13861,7 @@ require_complete_types_for_parms (tree parms)
 	  relayout_decl (parms);
 	  DECL_ARG_TYPE (parms) = type_passed_as (TREE_TYPE (parms));
 
+	  abstract_virtuals_error (parms, TREE_TYPE (parms));
 	  maybe_warn_parm_abi (TREE_TYPE (parms),
 			       DECL_SOURCE_LOCATION (parms));
 	}
@@ -14109,9 +14099,6 @@ grokparms (tree parmlist, tree *parms)
 	      type = build_pointer_type (type);
 	      TREE_TYPE (decl) = type;
 	    }
-	  else if (abstract_virtuals_error (decl, type))
-	    /* Ignore any default argument.  */
-	    init = NULL_TREE;
 	  else if (cxx_dialect < cxx17 && INDIRECT_TYPE_P (type))
 	    {
 	      /* Before C++17 DR 393:
@@ -17427,9 +17414,6 @@ complete_vars (tree type)
       else
 	ix++;
     }
-
-  /* Check for pending declarations which may have abstract type.  */
-  complete_type_check_abstract (type);
 }
 
 /* If DECL is of a type which needs a cleanup, build and return an
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a932c2133e1..1babf833d32 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14932,9 +14932,6 @@ tsubst_arg_types (tree arg_types,
           }
         return error_mark_node;
     }
-    /* DR 657. */
-    if (abstract_virtuals_error_sfinae (ACU_PARM, type, complain))
-      return error_mark_node;
 
     /* Do array-to-pointer, function-to-pointer conversion, and ignore
        top-level qualifiers as required.  */
@@ -15052,9 +15049,6 @@ tsubst_function_type (tree t,
 	}
       return error_mark_node;
     }
-  /* And DR 657. */
-  if (abstract_virtuals_error_sfinae (ACU_RETURN, return_type, complain))
-    return error_mark_node;
 
   if (!late_return_type_p)
     {
@@ -15880,9 +15874,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    return error_mark_node;
 	  }
 
-	if (abstract_virtuals_error_sfinae (ACU_ARRAY, type, complain))
-	  return error_mark_node;
-
 	r = build_cplus_array_type (type, domain);
 
 	if (!valid_array_size_p (input_location, r, in_decl,
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 445e2a211c8..412869946a5 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -123,123 +123,6 @@ cxx_readonly_error (location_t loc, tree arg, enum lvalue_use errstring)
     readonly_error (loc, arg, errstring);
 }
 
-/* Structure that holds information about declarations whose type was
-   incomplete and we could not check whether it was abstract or not.  */
-
-struct GTY((chain_next ("%h.next"), for_user)) pending_abstract_type {
-  /* Declaration which we are checking for abstractness. It is either
-     a DECL node, or an IDENTIFIER_NODE if we do not have a full
-     declaration available.  */
-  tree decl;
-
-  /* Type which will be checked for abstractness.  */
-  tree type;
-
-  /* Kind of use in an unnamed declarator.  */
-  enum abstract_class_use use;
-
-  /* Position of the declaration. This is only needed for IDENTIFIER_NODEs,
-     because DECLs already carry locus information.  */
-  location_t locus;
-
-  /* Link to the next element in list.  */
-  struct pending_abstract_type* next;
-};
-
-struct abstract_type_hasher : ggc_ptr_hash<pending_abstract_type>
-{
-  typedef tree compare_type;
-  static hashval_t hash (pending_abstract_type *);
-  static bool equal (pending_abstract_type *, tree);
-};
-
-/* Compute the hash value of the node VAL. This function is used by the
-   hash table abstract_pending_vars.  */
-
-hashval_t
-abstract_type_hasher::hash (pending_abstract_type *pat)
-{
-  return (hashval_t) TYPE_UID (pat->type);
-}
-
-
-/* Compare node VAL1 with the type VAL2. This function is used by the
-   hash table abstract_pending_vars.  */
-
-bool
-abstract_type_hasher::equal (pending_abstract_type *pat1, tree type2)
-{
-  return (pat1->type == type2);
-}
-
-/* Hash table that maintains pending_abstract_type nodes, for which we still
-   need to check for type abstractness.  The key of the table is the type
-   of the declaration.  */
-static GTY (()) hash_table<abstract_type_hasher> *abstract_pending_vars = NULL;
-
-static int abstract_virtuals_error_sfinae (tree, tree, abstract_class_use, tsubst_flags_t);
-
-/* This function is called after TYPE is completed, and will check if there
-   are pending declarations for which we still need to verify the abstractness
-   of TYPE, and emit a diagnostic (through abstract_virtuals_error) if TYPE
-   turned out to be incomplete.  */
-
-void
-complete_type_check_abstract (tree type)
-{
-  struct pending_abstract_type *pat;
-  location_t cur_loc = input_location;
-
-  gcc_assert (COMPLETE_TYPE_P (type));
-
-  if (!abstract_pending_vars)
-    return;
-
-  /* Retrieve the list of pending declarations for this type.  */
-  pending_abstract_type **slot
-    = abstract_pending_vars->find_slot_with_hash (type, TYPE_UID (type),
-						  NO_INSERT);
-  if (!slot)
-    return;
-  pat = *slot;
-  gcc_assert (pat);
-
-  /* If the type is not abstract, do not do anything.  */
-  if (CLASSTYPE_PURE_VIRTUALS (type))
-    {
-      struct pending_abstract_type *prev = 0, *next;
-
-      /* Reverse the list to emit the errors in top-down order.  */
-      for (; pat; pat = next)
-	{
-	  next = pat->next;
-	  pat->next = prev;
-	  prev = pat;
-	}
-      pat = prev;
-
-      /* Go through the list, and call abstract_virtuals_error for each
-	element: it will issue a diagnostic if the type is abstract.  */
-      while (pat)
-	{
-	  gcc_assert (type == pat->type);
-
-	  /* Tweak input_location so that the diagnostic appears at the correct
-	    location. Notice that this is only needed if the decl is an
-	    IDENTIFIER_NODE.  */
-	  input_location = pat->locus;
-	  abstract_virtuals_error_sfinae (pat->decl, pat->type, pat->use,
-					  tf_warning_or_error);
-	  pat = pat->next;
-	}
-    }
-
-  abstract_pending_vars->clear_slot (slot);
-
-  input_location = cur_loc;
-}
-
-
 /* If TYPE has abstract virtual functions, issue an error about trying
    to create an object of that type.  DECL is the object declared, or
    NULL_TREE if the declaration is unavailable, in which case USE specifies
@@ -252,6 +135,13 @@ abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
 {
   vec<tree, va_gc> *pure;
 
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      decl = NULL_TREE;
+      use = ACU_ARRAY;
+      type = strip_array_types (type);
+    }
+
   /* This function applies only to classes. Any other entity can never
      be abstract.  */
   if (!CLASS_TYPE_P (type))
@@ -266,38 +156,6 @@ abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
     complete_type (type);
 #endif
 
-  /* If the type is incomplete, we register it within a hash table,
-     so that we can check again once it is completed. This makes sense
-     only for objects for which we have a declaration or at least a
-     name.  */
-  if (!COMPLETE_TYPE_P (type) && (complain & tf_error))
-    {
-      struct pending_abstract_type *pat;
-
-      gcc_assert (!decl || DECL_P (decl) || identifier_p (decl));
-
-      if (!abstract_pending_vars)
-	abstract_pending_vars
-	  = hash_table<abstract_type_hasher>::create_ggc (31);
-
-      pending_abstract_type **slot
-       	= abstract_pending_vars->find_slot_with_hash (type, TYPE_UID (type),
-						      INSERT);
-
-      pat = ggc_alloc<pending_abstract_type> ();
-      pat->type = type;
-      pat->decl = decl;
-      pat->use = use;
-      pat->locus = ((decl && DECL_P (decl))
-		    ? DECL_SOURCE_LOCATION (decl)
-		    : input_location);
-
-      pat->next = *slot;
-      *slot = pat;
-
-      return 0;
-    }
-
   if (!TYPE_SIZE (type))
     /* TYPE is being defined, and during that time
        CLASSTYPE_PURE_VIRTUALS holds the inline friends.  */
@@ -2594,6 +2452,3 @@ require_complete_eh_spec_types (tree fntype, tree decl)
 	}
     }
 }
-
-
-#include "gt-cp-typeck2.h"
diff --git a/gcc/testsuite/g++.dg/other/abstract1.C b/gcc/testsuite/g++.dg/other/abstract1.C
index 53d767acd45..6ded7ec7547 100644
--- a/gcc/testsuite/g++.dg/other/abstract1.C
+++ b/gcc/testsuite/g++.dg/other/abstract1.C
@@ -5,34 +5,38 @@
 // c++/9256: Make sure that a pointer to an array of abstract elements
 //  cannot be created, not even during template substitution (DR337).
 
+// Changed massively by P0929R2: now only creating an object of the array type
+// is ill-formed, not merely forming the array type.
+
 struct Abstract { virtual void f() = 0; };  // { dg-message "note" } 
 struct Complete { void f(); };
 
 
 /*
  * TEST 1
- * Arrays of abstract elements cannot be declared.
+ * Arrays of abstract elements cannot be defined.
  */
 
 Abstract a0[2];        // { dg-error "" }
-Abstract (*a1)[2];     // { dg-error "" }
-Abstract (**a2)[2];    // { dg-error "" }
-Abstract (***a3)[2];   // { dg-error "" }
+Abstract (*a1)[2];
+Abstract (**a2)[2];
+Abstract (***a3)[2];
 Abstract *a4;
 Abstract *a5[2];
-Abstract (*a6[2])[2];  // { dg-error "" }
+Abstract (*a6[2])[2];
 Abstract **a7[2];
-Abstract *(*a8[2])[2];  
-Abstract (**a9[2])[2]; // { dg-error "" }
+Abstract *(*a8[2])[2];
+Abstract (**a9[2])[2];
 
 /*
  * TEST 2
- * If a pointer to an array of abstract elements is created during template
+ * If an array of abstract elements is created during template
  *  instantiation, an error should occur.
  */
 
 template <class T> struct K {
-  T (*a)[2];   // { dg-error "abstract class type" }
+  T (*a1)[2];
+  T (a2)[2];   // { dg-error "abstract" }
 };
 
 template struct K<Abstract>;  // { dg-message "required" }
@@ -41,8 +45,9 @@ template struct K<Abstract>;  // { dg-message "required" }
 
 /*
  * TEST 3
- * Deducing an array of abstract elements during type deduction is a silent
- *  failure (rejects overload).
+
+ * Deducing an array of abstract elements during type deduction is no longer a
+ *  silent failure.
  */
 
 template <bool> struct StaticAssert;
@@ -54,6 +59,6 @@ typedef struct { char x[2]; } No;
 template<typename U> No  is_abstract(U (*k)[1]);
 template<typename U> Yes is_abstract(...);
 
-StaticAssert<sizeof(is_abstract<Abstract>(0)) == sizeof(Yes)> b1;
+StaticAssert<sizeof(is_abstract<Abstract>(0)) == sizeof(No)> b1;
 StaticAssert<sizeof(is_abstract<Complete>(0)) == sizeof(No)> b2;
 StaticAssert<sizeof(is_abstract<int>(0)) == sizeof(No)> b3;
diff --git a/gcc/testsuite/g++.dg/other/abstract2.C b/gcc/testsuite/g++.dg/other/abstract2.C
index 60a4e41b5a9..0a8009e9bb3 100644
--- a/gcc/testsuite/g++.dg/other/abstract2.C
+++ b/gcc/testsuite/g++.dg/other/abstract2.C
@@ -5,54 +5,59 @@
 namespace N1 {
   struct X;
 
-  struct Y1 {
-    void g(X parm1);         // { dg-error "abstract" }
-    void g(X parm2[2]);      // { dg-error "abstract" }
-    void g(X (*parm3)[2]);   // { dg-error "abstract" }
+  struct X {  // { dg-message "note" }
+    virtual void xfunc(void) = 0;  // { dg-message "note" }
   };
 
+  struct Y1 {
+    void g(X parm1) {}         // { dg-error "abstract" }
+    void g(X parm2[2]) {}
+    void g(X (*parm3)[2]) {}
+  };
 
   template <int N>
   struct Y2 {
-    void g(X parm4);         // { dg-error "abstract" }
-    void g(X parm5[2]);      // { dg-error "abstract" }
-    void g(X (*parm6)[2]);   // { dg-error "abstract" }
+    void g(X parm4) {}         // { dg-error "abstract" }
+    void g(X parm5[2]) {}
+    void g(X (*parm6)[2]) {}
   };
 
-  struct X {  // { dg-message "note" }
-    virtual void xfunc(void) = 0;  // { dg-message "note" }
-  };
+  template struct Y2<42>;
 }
 
 namespace N2 {
   struct X1 { // { dg-message "note" }
     virtual void xfunc(void) = 0;  // { dg-message "note" }
-    void g(X1 parm7);        // { dg-error "abstract" }
-    void g(X1 parm8[2]);     // { dg-error "abstract" }
-    void g(X1 (*parm9)[2]);  // { dg-error "abstract" }
+    void g(X1 parm7) {}        // { dg-error "abstract" }
+    void g(X1 parm8[2]) {}
+    void g(X1 (*parm9)[2]) {}
   };
 
   template <int N>
   struct X2 { // { dg-message "note" }
     virtual void xfunc(void) = 0; // { dg-message "note" }
-    void g(X2 parm10);        // { dg-error "abstract" }
-    void g(X2 parm11[2]);     // { dg-error "abstract" }
-    void g(X2 (*parm12)[2]);  // { dg-error "abstract" }
+    void g(X2 parm10) {}        // { dg-error "abstract" }
+    void g(X2 parm11[2]) {}
+    void g(X2 (*parm12)[2]) {}
   };
+
+  template struct X2<42>;
 }
 
 namespace N3 {
   struct X { // { dg-message "note" }
     virtual void xfunc(void) = 0;  // { dg-message "note" }
   };
-  void g(X parm13);          // { dg-error "abstract" }
-  void g(X parm14[2]);       // { dg-error "abstract" }
-  void g(X (*parm15)[2]);    // { dg-error "abstract" }
-
-  template <int N> 
-  void g(X parm16);          // { dg-error "abstract" }
-  template <int N> 
-  void g(X parm17[2]);       // { dg-error "abstract" }
-  template <int N> 
-  void g(X (*parm18)[2]);    // { dg-error "abstract" }
+  void g(X parm13) {}          // { dg-error "abstract" }
+  void g(X parm14[2]) {}
+  void g(X (*parm15)[2]) {}
+
+  template <int N>
+  void g(X parm16) {}          // { dg-error "abstract" }
+  template <int N>
+  void g(X parm17[2]) {}
+  template <int N>
+  void g(X (*parm18)[2]) {}
+
+  template void g<42>(X);
 }
diff --git a/gcc/testsuite/g++.dg/other/abstract4.C b/gcc/testsuite/g++.dg/other/abstract4.C
index 68b2eb27b8c..6a8c8c75918 100644
--- a/gcc/testsuite/g++.dg/other/abstract4.C
+++ b/gcc/testsuite/g++.dg/other/abstract4.C
@@ -13,6 +13,6 @@ struct Abs
 
 int main()
 {
-  S<Abs(int)> s;     // { dg-error "abstract" }
-  foo<Abs(int)>();   // { dg-error "abstract" }
+  S<Abs(int)> s;
+  foo<Abs(int)>();
 }
diff --git a/gcc/testsuite/g++.dg/other/abstract5.C b/gcc/testsuite/g++.dg/other/abstract5.C
index d13dd9e5160..c17d60d3a3a 100644
--- a/gcc/testsuite/g++.dg/other/abstract5.C
+++ b/gcc/testsuite/g++.dg/other/abstract5.C
@@ -3,4 +3,4 @@ struct A
   virtual void f() = 0;
 };
 
-typedef A (*fp)();		// { dg-error "abstract" }
+typedef A (*fp)();
diff --git a/gcc/testsuite/g++.dg/other/abstract8.C b/gcc/testsuite/g++.dg/other/abstract8.C
new file mode 100644
index 00000000000..bc5afbbdc7f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/abstract8.C
@@ -0,0 +1,40 @@
+// P0929R2: Checking for abstract class types.
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -Wno-return-type }
+
+struct A
+{
+ virtual void f() = 0;
+};
+
+struct B
+{
+  A a;				// { dg-error "abstract" }
+  A ar[4];			// { dg-error "abstract" }
+};
+
+using Aa = A[4];		// OK
+Aa* aap;			// OK
+
+extern A a;			// OK
+extern Aa aa;			// OK
+A f();				// OK
+void g(A);			// OK
+
+A a;				// { dg-error "abstract" }
+Aa aa;				// { dg-error "abstract" }
+A f() { }			// { dg-error "abstract" }
+void g(A) { }			// { dg-error "abstract" }
+
+int main()
+{
+  (A(a));			// { dg-error "abstract" }
+  A{};				// { dg-error "abstract" }
+  static_cast<A>(a);		// { dg-error "abstract" }
+  Aa{};				// { dg-error "abstract" }
+  f();				// { dg-error "abstract" }
+  decltype(f())* p;		// OK
+  g(a);				// { dg-error "abstract" }
+
+  throw a;			// { dg-error "abstract" }
+}
diff --git a/gcc/testsuite/g++.dg/template/sfinae-dr657.C b/gcc/testsuite/g++.dg/template/sfinae-dr657.C
index b78b5a919c1..36c11e65918 100644
--- a/gcc/testsuite/g++.dg/template/sfinae-dr657.C
+++ b/gcc/testsuite/g++.dg/template/sfinae-dr657.C
@@ -1,6 +1,7 @@
-// DR 657
-// Test that a return or parameter type with abstract class type causes a
-// deduction failure.
+// DR 657 SUPERSEDED BY DR 1646
+// Test that a return or parameter type with abstract class type DOES NOT cause
+// a deduction failure, but there is no implicit conversion sequence for
+// a parameter of abstract class type.
 
 struct A
 {
@@ -17,6 +18,6 @@ template<class T> int arg(...);
 
 int main()
 {
-  int i = declval<A>();
+  int i = declval<A>();		// { dg-error "ambiguous" }
   i = arg<A>(1);
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.other/decl3.C b/gcc/testsuite/g++.old-deja/g++.other/decl3.C
index bdcfcb02c6f..4534bd16aad 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/decl3.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/decl3.C
@@ -13,7 +13,7 @@ struct cow_t { // { dg-message "pure" }
 
 int main()
 {
-  cow_t cow[2];  // { dg-error "invalid abstract type" }
+  cow_t cow[2];  // { dg-error "abstract" }
   cow[0].f();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/20_util/result_of/sfinae_friendly_1.cc b/libstdc++-v3/testsuite/20_util/result_of/sfinae_friendly_1.cc
index 4b44b797b97..cce481292bd 100644
--- a/libstdc++-v3/testsuite/20_util/result_of/sfinae_friendly_1.cc
+++ b/libstdc++-v3/testsuite/20_util/result_of/sfinae_friendly_1.cc
@@ -379,19 +379,19 @@ static_assert(is_type<std::result_of<ident_functor(const volatile Abstract&)>,
 	      const volatile Abstract&>(), "Error!");
 
 static_assert(!has_type<std::result_of<ident_functor(int(&&)[1])>>(), "Error!");
-static_assert(!has_type<std::result_of<ident_functor(Abstract&&)>>(), "Error!");
+static_assert(is_type<std::result_of<ident_functor(Abstract&&)>,Abstract>(), "Error!");
 static_assert(!has_type<std::result_of<ident_functor(const int(&&)[1])>>(),
 	      "Error!");
-static_assert(!has_type<std::result_of<ident_functor(const Abstract&&)>>(),
+static_assert(is_type<std::result_of<ident_functor(const Abstract&&)>,const Abstract>(),
 	      "Error!");
 static_assert(!has_type<std::result_of<ident_functor_noref(int(&)[1])>>(),
 	      "Error!");
 static_assert(!has_type<std::result_of<ident_functor_noref
 	      (const int(&)[1])>>(), "Error!");
-static_assert(!has_type<std::result_of<ident_functor_noref(Abstract&)>>(),
+static_assert(is_type<std::result_of<ident_functor_noref(Abstract&)>,Abstract>(),
 	      "Error!");
-static_assert(!has_type<std::result_of
-	      <ident_functor_noref(const Abstract&)>>(), "Error!");
+static_assert(is_type<std::result_of
+	      <ident_functor_noref(const Abstract&)>,const Abstract>(), "Error!");
 static_assert(!has_type<std::result_of<ident_functor_noref(void(&)())>>(),
 	      "Error!");
 static_assert(!has_type<std::result_of<ident_functor_noref(void(&&)())>>(),


More information about the Libstdc++-cvs mailing list