From patchwork Sun Mar 17 01:33:12 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 228256 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 267052C00AE for ; Sun, 17 Mar 2013 12:33:36 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1364088817; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Message-ID:Date:From:User-Agent:MIME-Version:To:Subject: References:In-Reply-To:Content-Type:Mailing-List:Precedence: List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=SF8dszp/d7sb/VxxHhJU19Oakn8=; b=sxcACCyR4EtT0gO J99UPP+fBQ5FwvNji/w928LFgi/flsR6Z8hzq9Nz3WVBtdfu5CDoSrJ+/1v3a6UD GEVj+IBRjjFa7+uj1fxvvjHuAzJVEDYur/WuZfaS/fwAAF/3nmtZao38f8ssw7Xf SRSxYB1CBCVlsNCRsO4aho4VUaG0= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Message-ID:Date:From:User-Agent:MIME-Version:To:Subject:References:In-Reply-To:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=dzFzyYuCvgQgU2mlQLRfcjDPCYNfBD/2ViyaHXCaFSunfnFO9uQ9+QYOQ1XMMM hsRc0ZXSxjQG4locYfsfJ1ErkQmkx8duQ+ciS0Swoi2Z5sWnXit660nmZrjd9SpB LvdKMcLYFCpvKcedHsKJuwFPDmunFBxkkMNvtoL5i9Q50=; Received: (qmail 16708 invoked by alias); 17 Mar 2013 01:33:27 -0000 Received: (qmail 16697 invoked by uid 22791); 17 Mar 2013 01:33:25 -0000 X-SWARE-Spam-Status: No, hits=-8.4 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, KHOP_THREADED, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_W, RP_MATCHES_RCVD, SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 17 Mar 2013 01:33:18 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r2H1XHTN009621 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Sat, 16 Mar 2013 21:33:17 -0400 Received: from [10.3.113.56] (ovpn-113-56.phx2.redhat.com [10.3.113.56]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r2H1XDn8025008 for ; Sat, 16 Mar 2013 21:33:16 -0400 Message-ID: <51451D58.9050500@redhat.com> Date: Sat, 16 Mar 2013 21:33:12 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; Linux i686; rv:21.0) Gecko/20100101 Thunderbird/21.0a2 MIME-Version: 1.0 To: gcc-patches List Subject: Re: C++ PATCH for DR 657 (abstract classes and sfinae) References: <5144C98F.7050704@redhat.com> In-Reply-To: <5144C98F.7050704@redhat.com> Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org While I was looking at this and 17232 I also decided to improve the abstract class diagnostics. Tested x86_64-pc-linux-gnu, applying to trunk. commit 3f00e78856a76cf45d56d548ebc77755dc1d0333 Author: Jason Merrill Date: Wed Feb 27 12:30:41 2013 -0500 * 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. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e2a96a5..39fb3df 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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) \ @@ -5986,7 +5999,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**, int); extern void check_narrowing (tree, tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index bf34585..fed101f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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; diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 216ec10..52ba1cd 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -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)) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 697f11f..679c47d 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2301,7 +2301,7 @@ build_new_1 (vec **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); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index fd1ad9b..4ffc353 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 58ebcc0..7fa5304 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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 diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 37c42e2..6ef46a1 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -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 *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 index 0000000..d13dd9e --- /dev/null +++ b/gcc/testsuite/g++.dg/other/abstract5.C @@ -0,0 +1,6 @@ +struct A +{ + virtual void f() = 0; +}; + +typedef A (*fp)(); // { dg-error "abstract" }