cp-tree.h (abstract_class_use): New enum.
authorJason Merrill <jason@redhat.com>
Sun, 17 Mar 2013 02:36:55 +0000 (22:36 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sun, 17 Mar 2013 02:36:55 +0000 (22:36 -0400)
* cp-tree.h (abstract_class_use): New enum.
* typeck2.c (pending_abstract_type): Add use field.
(abstract_virtuals_error_sfinae): Add overloads taking
abstract_class_use instead of tree.
* typeck.c (build_static_cast_1): Call it.
* except.c (is_admissible_throw_operand_or_catch_parameter): Call it.
* pt.c: Adjust calls.
* decl.c (cp_finish_decl): Don't handle functions specially.
(grokdeclarator): Always check return type.
* init.c (build_new_1): Adjust call.

From-SVN: r196735

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/except.c
gcc/cp/init.c
gcc/cp/pt.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/other/abstract5.C [new file with mode: 0644]

index 20414dc..b57800e 100644 (file)
@@ -1,5 +1,16 @@
 2013-03-16  Jason Merrill  <jason@redhat.com>
 
+       * cp-tree.h (abstract_class_use): New enum.
+       * typeck2.c (pending_abstract_type): Add use field.
+       (abstract_virtuals_error_sfinae): Add overloads taking
+       abstract_class_use instead of tree.
+       * typeck.c (build_static_cast_1): Call it.
+       * except.c (is_admissible_throw_operand_or_catch_parameter): Call it.
+       * pt.c: Adjust calls.
+       * decl.c (cp_finish_decl): Don't handle functions specially.
+       (grokdeclarator): Always check return type.
+       * init.c (build_new_1): Adjust call.
+
        DR 337
        PR c++/17232
        * pt.c (tsubst) [ARRAY_TYPE]: Use abstract_virtuals_error_sfinae.
index d9496d2..53940a6 100644 (file)
@@ -463,6 +463,19 @@ typedef enum impl_conv_void {
   ICV_THIRD_IN_FOR     /* for increment expression */
 } impl_conv_void;
 
+/* Possible invalid uses of an abstract class that might not have a
+   specific associated declaration.  */
+typedef enum abstract_class_use {
+  ACU_UNKNOWN,                 /* unknown or decl provided */
+  ACU_CAST,                    /* cast to abstract class */
+  ACU_NEW,                     /* new-expression of abstract class */
+  ACU_THROW,                   /* throw-expression of abstract class */
+  ACU_CATCH,                   /* catch-parameter of abstract class */
+  ACU_ARRAY,                   /* array of abstract class */
+  ACU_RETURN,                  /* return type of abstract class */
+  ACU_PARM                     /* parameter type of abstract class */
+} abstract_class_use;
+
 /* Macros for access to language-specific slots in an identifier.  */
 
 #define IDENTIFIER_NAMESPACE_BINDINGS(NODE)    \
@@ -5983,7 +5996,9 @@ extern tree binfo_or_else                 (tree, tree);
 extern void cxx_readonly_error                 (tree, enum lvalue_use);
 extern void complete_type_check_abstract       (tree);
 extern int abstract_virtuals_error             (tree, tree);
+extern int abstract_virtuals_error             (abstract_class_use, tree);
 extern int abstract_virtuals_error_sfinae      (tree, tree, tsubst_flags_t);
+extern int abstract_virtuals_error_sfinae      (abstract_class_use, tree, tsubst_flags_t);
 
 extern tree store_init_value                   (tree, tree, vec<tree, va_gc>**, int);
 extern void check_narrowing                    (tree, tree);
index 0e66840..40152b1 100644 (file)
@@ -6434,11 +6434,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
       /* 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.  */
-      if (TREE_CODE (type) == FUNCTION_TYPE
-         || TREE_CODE (type) == METHOD_TYPE)
-       abstract_virtuals_error (decl, TREE_TYPE (type));
-      else
-       abstract_virtuals_error (decl, type);
+      abstract_virtuals_error (decl, type);
 
       if (TREE_TYPE (decl) == error_mark_node)
        /* No initialization required.  */
@@ -8656,6 +8652,7 @@ grokdeclarator (const cp_declarator *declarator,
   bool template_type_arg = false;
   bool template_parm_flag = false;
   bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
+  source_location saved_loc = input_location;
   const char *errmsg;
 
   signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
@@ -9340,7 +9337,6 @@ grokdeclarator (const cp_declarator *declarator,
   if (declspecs->std_attributes)
     {
       /* Apply the c++11 attributes to the type preceding them.  */
-      source_location saved_loc = input_location;
       input_location = declspecs->locations[ds_std_attribute];
       decl_attributes (&type, declspecs->std_attributes, 0);
       input_location = saved_loc;
@@ -9428,11 +9424,10 @@ grokdeclarator (const cp_declarator *declarator,
                error ("%qs declared as function returning an array", name);
                return error_mark_node;
              }
-           /* When decl_context == NORMAL we emit a better error message
-              later in abstract_virtuals_error.  */
-           if (decl_context == TYPENAME && ABSTRACT_CLASS_TYPE_P (type))
-             error ("%qs declared as function returning an abstract "
-                    "class type", name);
+
+           input_location = declspecs->locations[ds_type_spec];
+           abstract_virtuals_error (ACU_RETURN, type);
+           input_location = saved_loc;
 
            /* Pick up type qualifiers which should be applied to `this'.  */
            memfn_quals = declarator->u.function.qualifiers;
index 216ec10..52ba1cd 100644 (file)
@@ -972,16 +972,8 @@ is_admissible_throw_operand_or_catch_parameter (tree t, bool is_throw)
   /* 10.4/3 An abstract class shall not be used as a parameter type,
            as a function return type or as type of an explicit
            conversion.  */
-  else if (ABSTRACT_CLASS_TYPE_P (type))
-    {
-      if (is_throw)
-       error ("expression %qE of abstract class type %qT cannot "
-              "be used in throw-expression", expr, type);
-      else
-       error ("cannot declare catch parameter to be of abstract "
-              "class type %qT", type);
-      return false;
-    }
+  else if (abstract_virtuals_error (is_throw ? ACU_THROW : ACU_CATCH, type))
+    return false;
   else if (!is_throw
           && TREE_CODE (type) == REFERENCE_TYPE
           && TYPE_REF_IS_RVALUE (type))
index 697f11f..679c47d 100644 (file)
@@ -2301,7 +2301,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
       return error_mark_node;
     }
 
-  if (abstract_virtuals_error_sfinae (NULL_TREE, elt_type, complain))
+  if (abstract_virtuals_error_sfinae (ACU_NEW, elt_type, complain))
     return error_mark_node;
 
   is_initialized = (type_build_ctor_call (elt_type) || *init != NULL);
index ce07fa4..edc2d0b 100644 (file)
@@ -10851,7 +10851,7 @@ tsubst_arg_types (tree arg_types,
         return error_mark_node;
     }
     /* DR 657. */
-    if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain))
+    if (abstract_virtuals_error_sfinae (ACU_PARM, type, complain))
       return error_mark_node;
     
     /* Do array-to-pointer, function-to-pointer conversion, and ignore
@@ -10930,7 +10930,7 @@ tsubst_function_type (tree t,
       return error_mark_node;
     }
   /* And DR 657. */
-  if (abstract_virtuals_error_sfinae (NULL_TREE, return_type, complain))
+  if (abstract_virtuals_error_sfinae (ACU_RETURN, return_type, complain))
     return error_mark_node;
 
   /* Substitute the argument types.  */
@@ -11654,7 +11654,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
            return error_mark_node;
          }
 
-       if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain))
+       if (abstract_virtuals_error_sfinae (ACU_ARRAY, type, complain))
          return error_mark_node;
 
        r = build_cplus_array_type (type, domain);
index 96e0ad8..3ced858 100644 (file)
@@ -6238,6 +6238,12 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
   if (TREE_CODE (type) == VOID_TYPE)
     return convert_to_void (expr, ICV_CAST, complain);
 
+  /* [class.abstract]
+     An abstract class shall not be used ... as the type of an explicit
+     conversion.  */
+  if (abstract_virtuals_error_sfinae (ACU_CAST, type, complain))
+    return error_mark_node;
+
   /* [expr.static.cast]
 
      An expression e can be explicitly converted to a type T using a
index dc17776..3bac67c 100644 (file)
@@ -141,6 +141,9 @@ struct GTY((chain_next ("%h.next"))) pending_abstract_type {
   /* Type which will be checked for abstractness.  */
   tree type;
 
+  /* Kind of use in an unnamed declarator.  */
+  abstract_class_use use;
+
   /* Position of the declaration. This is only needed for IDENTIFIER_NODEs,
      because DECLs already carry locus information.  */
   location_t locus;
@@ -181,6 +184,7 @@ pat_compare (const void* val1, const void* val2)
 static GTY ((param_is (struct pending_abstract_type)))
 htab_t 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
@@ -231,7 +235,8 @@ complete_type_check_abstract (tree type)
            location. Notice that this is only needed if the decl is an
            IDENTIFIER_NODE.  */
          input_location = pat->locus;
-         abstract_virtuals_error (pat->decl, pat->type);
+         abstract_virtuals_error_sfinae (pat->decl, pat->type, pat->use,
+                                         tf_warning_or_error);
          pat = pat->next;
        }
     }
@@ -244,11 +249,13 @@ complete_type_check_abstract (tree type)
 
 /* 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.  Returns 1 if an error
-   occurred; zero if all was well.  */
+   NULL_TREE if the declaration is unavailable, in which case USE specifies
+   the kind of invalid use.  Returns 1 if an error occurred; zero if
+   all was well.  */
 
-int
-abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
+static int
+abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
+                               tsubst_flags_t complain)
 {
   vec<tree, va_gc> *pure;
 
@@ -284,6 +291,7 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
       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);
@@ -312,8 +320,14 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
        error ("cannot declare variable %q+D to be of abstract "
               "type %qT", decl, type);
       else if (TREE_CODE (decl) == PARM_DECL)
-       error ("cannot declare parameter %q+D to be of abstract type %qT",
-              decl, type);
+       {
+         if (DECL_NAME (decl))
+           error ("cannot declare parameter %q+D to be of abstract type %qT",
+                  decl, type);
+         else
+           error ("cannot declare parameter to be of abstract type %qT",
+                  type);
+       }
       else if (TREE_CODE (decl) == FIELD_DECL)
        error ("cannot declare field %q+D to be of abstract type %qT",
               decl, type);
@@ -328,8 +342,34 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
       else
        error ("invalid abstract type for %q+D", decl);
     }
-  else
-    error ("cannot allocate an object of abstract type %qT", type);
+  else switch (use)
+    {
+    case ACU_ARRAY:
+      error ("creating array of %qT, which is an abstract class type", type);
+      break;
+    case ACU_CAST:
+      error ("invalid cast to abstract class type %qT", type);
+      break;
+    case ACU_NEW:
+      error ("invalid new-expression of abstract class type %qT", type);
+      break;
+    case ACU_RETURN:
+      error ("invalid abstract return type %qT", type);
+      break;
+    case ACU_PARM:
+      error ("invalid abstract parameter type %qT", type);
+      break;
+    case ACU_THROW:
+      error ("expression of abstract class type %qT cannot "
+            "be used in throw-expression", type);
+      break;
+    case ACU_CATCH:
+      error ("cannot declare catch parameter to be of abstract "
+            "class type %qT", type);
+      break;
+    default:
+      error ("cannot allocate an object of abstract type %qT", type);
+    }
 
   /* Only go through this once.  */
   if (pure->length ())
@@ -351,14 +391,24 @@ abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
         again.  */
       pure->truncate (0);
     }
-  else
-    inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)),
-           "  since type %qT has pure virtual functions",
-           type);
 
   return 1;
 }
 
+int
+abstract_virtuals_error_sfinae (tree decl, tree type, tsubst_flags_t complain)
+{
+  return abstract_virtuals_error_sfinae (decl, type, ACU_UNKNOWN, complain);
+}
+
+int
+abstract_virtuals_error_sfinae (abstract_class_use use, tree type,
+                               tsubst_flags_t complain)
+{
+  return abstract_virtuals_error_sfinae (NULL_TREE, type, use, complain);
+}
+
+
 /* Wrapper for the above function in the common case of wanting errors.  */
 
 int
@@ -367,6 +417,12 @@ abstract_virtuals_error (tree decl, tree type)
   return abstract_virtuals_error_sfinae (decl, type, tf_warning_or_error);
 }
 
+int
+abstract_virtuals_error (abstract_class_use use, tree type)
+{
+  return abstract_virtuals_error_sfinae (use, type, tf_warning_or_error);
+}
+
 /* Print an error message for invalid use of an incomplete type.
    VALUE is the expression that was used (or 0 if that isn't known)
    and TYPE is the type that was invalid.  DIAG_KIND indicates the
@@ -1733,7 +1789,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
 
   if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
     return error_mark_node;
-  if (abstract_virtuals_error_sfinae (NULL_TREE, type, complain))
+  if (abstract_virtuals_error_sfinae (ACU_CAST, type, complain))
     return error_mark_node;
 
   /* [expr.type.conv]
diff --git a/gcc/testsuite/g++.dg/other/abstract5.C b/gcc/testsuite/g++.dg/other/abstract5.C
new file mode 100644 (file)
index 0000000..d13dd9e
--- /dev/null
@@ -0,0 +1,6 @@
+struct A
+{
+  virtual void f() = 0;
+};
+
+typedef A (*fp)();             // { dg-error "abstract" }