From patchwork Fri Sep 30 17:39:47 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 677158 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3slzH82Tdbz9s4n for ; Sat, 1 Oct 2016 03:40:18 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=QEw7+oOh; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to:cc :from:subject:message-id:date:mime-version:content-type; q=dns; s=default; b=sgaDYqWhZhi1ZC3mpsJOF00C5U19RAg5EiRVQCTuVTXbZuVNKQ IypuoFvVChS47DAL/4NSpfpLYxmNULX8UZo9j+OlDZ+PVBWpb4kBA1pxnVMgYrZS ClreBKSvRTV+GUkfZeeuA9tUrABXoOHJxzU9KdDB0946KguQAqkW0mUNI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to:cc :from:subject:message-id:date:mime-version:content-type; s= default; bh=bYLTIm1j41pWg1sO8icumiMunU0=; b=QEw7+oOhVfyBGkMpVPTd nxcHak4P/65cG66IqLFaHJ2dN/eKv2R3/Wj7iBTvcfTjNoFFB0/x/CjT+9OVEI/n 0b8UFFZOhlQtRq7+bx29kUEjn7uYMRRaB+geF59shXWeSj6vdomxB6GsgY17djKf g9yx8+7BsY89gJD5UuMaHOk= Received: (qmail 101705 invoked by alias); 30 Sep 2016 17:40:01 -0000 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 Received: (qmail 101666 invoked by uid 89); 30 Sep 2016 17:40:00 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.6 required=5.0 tests=BAYES_20, FREEMAIL_FROM, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_LOW, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=no version=3.3.2 spammy=cond_expr, COND_EXPR, nonexistent, 17047 X-HELO: mail-qk0-f173.google.com Received: from mail-qk0-f173.google.com (HELO mail-qk0-f173.google.com) (209.85.220.173) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 30 Sep 2016 17:39:50 +0000 Received: by mail-qk0-f173.google.com with SMTP id z190so113452744qkc.3 for ; Fri, 30 Sep 2016 10:39:50 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:to:cc:from:subject:message-id:date :user-agent:mime-version; bh=AJHsMH2TzcljhB6g+T2twoia6tvWUHSu480j9TZKCQ4=; b=kPmEQSmwi8SXxvYdDBafja/w2S0YWVvM/PheRSbgiS+nFcXpzdALh8xpOuhcyz7Bo8 Ge/sFfJuGgLjdincLNh0c7eJP4rf9Tnr5cA4+qR89q2ac9fgTKi8vevXyF5PaaOX8Rir WyD8SG+fGsQkdFhhfkFyYLNpEmfGZE89CqwVT3xVIMcUqIZq1IwFNj2cRjpiMpo6gPF7 m5ccVTAysM7Xc7LNvHuTsnjtRUFuQRBhPAcVSrawVdCdHRAZ4k35fwcDSpPBorEgz1zq ZCK5J3OJlKxQmvfUgf9NOFY1mAyQ3s27/D9wFwtjX6SAdMq/HNDZKmiQwJApraoWV0kl ht1w== X-Gm-Message-State: AA6/9RltP41m4qKycVHkFtuybU8yOTB7t0gpo768wXZ5JWmPGnM2lANoqhRt0C1sUHpwpQ== X-Received: by 10.55.201.141 with SMTP id m13mr8164770qkl.66.1475257188920; Fri, 30 Sep 2016 10:39:48 -0700 (PDT) Received: from ?IPv6:2601:181:c003:1930:3fe6:c217:b86a:6e86? ([2601:181:c003:1930:3fe6:c217:b86a:6e86]) by smtp.googlemail.com with ESMTPSA id m58sm10666143qtm.42.2016.09.30.10.39.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 30 Sep 2016 10:39:48 -0700 (PDT) To: Jason Merrill Cc: GCC Patches From: Nathan Sidwell Subject: [C++/66443] deleted ctor and vbase construction Message-ID: <362b3538-6219-ded5-1588-5baa113919ae@acm.org> Date: Fri, 30 Sep 2016 13:39:47 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.3.0 MIME-Version: 1.0 PR 66443 concerns C++14 DR1611. It is now permitted to use the base-ctor of an abstract class whos complete ctor is deleted because of a virtual base issue. Specifically, given class A { A (int); // no default ctor in C++14 }; class B : virtual A { virtual void Foo () = 0; // abstract // B::B deleted because there's no A::A() }; class C: B { virtual void Foo (); // not abstract C () : A(1) // explicit vbase construction {} }; Here, there's no way that B's complete object constructor can be called -- it's an abstract class, so no complete B objects can exist. B's as-a-base constructor never constructs the A base, because its a virtual base. So the missing 'A::A()' is never needed. C's constructors must explicitly construct the A base using the available constructors. the trickiness is that we create both base and complete constructors by building a more generic constructor, cloning it substituting the 'in-charge' parameter value and then allowing optimization to remove unreachable code in the two instances. (see below for why not have the complete-ctor tail call the base-ctor.) This patch adds a new FUNCTION_DECL flag and accessor 'DECL_BASE_FN_UNDELETED'. In the example above, this is true for B's generic constructor. When we actually need a B constructor (the bodies are created lazily), we check DECL_BASE_FN_UNDELETED to see whether we need to do something 'interesting'. If we do, and its the base-ctor we don't do the usual 'create generic body, clone it' scheme. Instead we create the base body explicitly, passing an new 'skip-vbases' flag, and thus never try and find 'A::A()' in this case. build_if_incharge needs tweaking, because the incharge parm only exists on the generic ctor. bootstrapped on x86_64-linux, ok? nathan [*] why not tail-call the as-base ctor after constructing the vbases? That would be fine for most cases, but we might need to provide a vtt pointer describing the complete object. Not sure if such a table exists right now. Anyway the more serios issue is varadic ctors. [without additional compiler magic] we can't tailcall from the complete ctor to the base ctor. 2016-09-30 Nathan Sidwell cp/ PR c++/66443 * cp-tree.h (lang_decl_fn): Add base_undeleted_p. (DECL_BASE_UNDELETED_FN): New. (emit_mem_initializer, finish_mem_initializers): Add skip vbases arg. * class.c (build_if_incharge): Allow no incharge parm when building undeleted base dtor directly. * decl2.c (mark_used): Don't complain about using an undeleted base ctor. * init.c (emit_mem_initializers): Add skip_vbases arg. Skip vbase construction if true. * method.c (do_build_copy_constructor): Add skip_vbases arg, pass it through. (synthesize_method): Skip vbases when we have a (synthesized_method_walk): Add vbase_deleted_p argument. Use it. (get_defaulted_eh_spec): Adjust synthesized_method_walk. (maybe_explain_implicit_delete, explain_implicit_non_constexpr, deduce_intheriting_ctor): Likewise. (implicitly_declare_fn): Determine DECL_BASE_UNDELETED_FN. * parser.c (cp_parser_ctor_initializer, cp_parser_mem_initializer_list): Adjust finish_mem_initializer call. * pt.c (tsubst_expr): Likewise. * semantics.c (finish_mem_initializers): Add skip_vbase parm, pass to emit_mem_initializers. testsuite. PR c++/66443 * g++.dg/cpp0x/pr66443-cxx11.C: New. * g++.dg/cpp1y/pr66443-cxx14.C: New * g++.dg/cpp1y/pr66443-cxx14-2.C: New. Index: cp/class.c =================================================================== --- cp/class.c (revision 240596) +++ cp/class.c (working copy) @@ -233,15 +233,27 @@ int n_inner_fields_searched = 0; tree build_if_in_charge (tree true_stmt, tree false_stmt) { - gcc_assert (DECL_HAS_IN_CHARGE_PARM_P (current_function_decl)); - tree cmp = build2 (NE_EXPR, boolean_type_node, - current_in_charge_parm, integer_zero_node); - tree type = unlowered_expr_type (true_stmt); - if (VOID_TYPE_P (type)) - type = unlowered_expr_type (false_stmt); - tree cond = build3 (COND_EXPR, type, - cmp, true_stmt, false_stmt); - return cond; + tree result; + + if (DECL_HAS_IN_CHARGE_PARM_P (current_function_decl)) + { + tree cmp = build2 (NE_EXPR, boolean_type_node, + current_in_charge_parm, integer_zero_node); + tree type = unlowered_expr_type (true_stmt); + if (VOID_TYPE_P (type)) + type = unlowered_expr_type (false_stmt); + result = build3 (COND_EXPR, type, cmp, true_stmt, false_stmt); + } + else + { + /* We must be building an undeleted base ctor. */ + gcc_assert (DECL_BASE_CONSTRUCTOR_P (current_function_decl) + && DECL_DELETED_FN (current_function_decl) + && DECL_BASE_UNDELETED_FN (current_function_decl)); + result = false_stmt; + } + + return result; } /* Convert to or from a base subobject. EXPR is an expression of type Index: cp/cp-tree.h =================================================================== --- cp/cp-tree.h (revision 240596) +++ cp/cp-tree.h (working copy) @@ -2297,6 +2297,7 @@ struct GTY(()) lang_decl_fn { unsigned static_function : 1; unsigned pure_virtual : 1; unsigned defaulted_p : 1; + unsigned base_undeleted_p : 1; unsigned has_in_charge_parm_p : 1; unsigned has_vtt_parm_p : 1; @@ -2306,7 +2307,7 @@ struct GTY(()) lang_decl_fn { unsigned this_thunk_p : 1; unsigned hidden_friend_p : 1; unsigned omp_declare_reduction_p : 1; - /* 2 spare bits on 32-bit hosts, 34 on 64-bit hosts. */ + /* 1 spare bit on 32-bit hosts, 33 on 64-bit hosts. */ /* For a non-thunk function decl, this is a tree list of friendly classes. For a thunk function decl, it is the @@ -3631,6 +3632,10 @@ more_aggr_init_expr_args_p (const aggr_i #define DECL_DELETED_FN(DECL) \ (LANG_DECL_FN_CHECK (DECL)->min.base.threadprivate_or_deleted_p) +/* Nonzero if the base-specific function is not deleted. */ +#define DECL_BASE_UNDELETED_FN(DECL) \ + (LANG_DECL_FN_CHECK (DECL)->base_undeleted_p) + /* Nonzero if DECL was declared with '= default' (maybe implicitly). */ #define DECL_DEFAULTED_FN(DECL) \ (LANG_DECL_FN_CHECK (DECL)->defaulted_p) @@ -5960,7 +5965,7 @@ extern tree do_friend (tree, tree, tr /* in init.c */ extern tree expand_member_init (tree); -extern void emit_mem_initializers (tree); +extern void emit_mem_initializers (tree, bool); extern tree build_aggr_init (tree, tree, int, tsubst_flags_t); extern int is_class_type (tree, int); @@ -6413,7 +6418,7 @@ extern tree finish_offsetof (tree, loc extern void finish_decl_cleanup (tree, tree); extern void finish_eh_cleanup (tree); extern void emit_associated_thunks (tree); -extern void finish_mem_initializers (tree); +extern void finish_mem_initializers (tree, bool); extern tree check_template_template_default_arg (tree); extern bool expand_or_defer_fn_1 (tree); extern void expand_or_defer_fn (tree); Index: cp/decl2.c =================================================================== --- cp/decl2.c (revision 240596) +++ cp/decl2.c (working copy) @@ -5132,38 +5132,37 @@ mark_used (tree decl, tsubst_flags_t com if (TREE_CODE (decl) == TEMPLATE_DECL) return true; - if (DECL_CLONED_FUNCTION_P (decl)) - TREE_USED (DECL_CLONED_FUNCTION (decl)) = 1; - /* Mark enumeration types as used. */ if (TREE_CODE (decl) == CONST_DECL) used_types_insert (DECL_CONTEXT (decl)); if (TREE_CODE (decl) == FUNCTION_DECL) - maybe_instantiate_noexcept (decl); - - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_DELETED_FN (decl)) { - if (DECL_ARTIFICIAL (decl)) + maybe_instantiate_noexcept (decl); + + if (!DECL_DELETED_FN (decl) && DECL_CLONED_FUNCTION_P (decl)) + TREE_USED (DECL_CLONED_FUNCTION (decl)) = 1; + + if (DECL_DELETED_FN (decl) + && !(DECL_BASE_UNDELETED_FN (decl) + && DECL_BASE_CONSTRUCTOR_P (decl))) { - if (DECL_OVERLOADED_OPERATOR_P (decl) == TYPE_EXPR + if (DECL_ARTIFICIAL (decl) + &&DECL_OVERLOADED_OPERATOR_P (decl) == TYPE_EXPR && LAMBDA_TYPE_P (DECL_CONTEXT (decl))) + /* We mark a lambda conversion op as deleted if we + can't generate it properly; see + maybe_add_lambda_conv_op. */ + sorry ("converting lambda that uses %<...%> to " + "function pointer"); + else if (complain & tf_error) { - /* We mark a lambda conversion op as deleted if we can't - generate it properly; see maybe_add_lambda_conv_op. */ - sorry ("converting lambda which uses %<...%> to " - "function pointer"); - return false; + error ("use of deleted function %qD", decl); + if (!maybe_explain_implicit_delete (decl)) + inform (DECL_SOURCE_LOCATION (decl), "declared here"); } + return false; } - if (complain & tf_error) - { - error ("use of deleted function %qD", decl); - if (!maybe_explain_implicit_delete (decl)) - inform (DECL_SOURCE_LOCATION (decl), "declared here"); - } - return false; } if (TREE_DEPRECATED (decl) && (complain & tf_warning) Index: cp/init.c =================================================================== --- cp/init.c (revision 240596) +++ cp/init.c (working copy) @@ -1093,7 +1093,7 @@ sort_mem_initializers (tree t, tree mem_ void_type_node for an empty list of arguments. */ void -emit_mem_initializers (tree mem_inits) +emit_mem_initializers (tree mem_inits, bool skip_vbases) { int flags = LOOKUP_NORMAL; @@ -1150,9 +1150,7 @@ emit_mem_initializers (tree mem_inits) } /* Initialize the base. */ - if (BINFO_VIRTUAL_P (subobject)) - construct_virtual_base (subobject, arguments); - else + if (!BINFO_VIRTUAL_P (subobject)) { tree base_addr; @@ -1166,6 +1164,8 @@ emit_mem_initializers (tree mem_inits) tf_warning_or_error); expand_cleanup_for_base (subobject, NULL_TREE); } + else if (!skip_vbases) + construct_virtual_base (subobject, arguments); } in_base_initializer = 0; Index: cp/method.c =================================================================== --- cp/method.c (revision 240596) +++ cp/method.c (working copy) @@ -49,7 +49,7 @@ enum mangling_flags }; static void do_build_copy_assign (tree); -static void do_build_copy_constructor (tree); +static void do_build_copy_constructor (tree, bool); static tree make_alias_for_thunk (tree); /* Called once to initialize method.c. */ @@ -532,7 +532,7 @@ add_one_base_init (tree binfo, tree parm constructor. */ static void -do_build_copy_constructor (tree fndecl) +do_build_copy_constructor (tree fndecl, bool skip_vbases) { tree parm = FUNCTION_FIRST_USER_PARM (fndecl); bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl); @@ -647,7 +647,7 @@ do_build_copy_constructor (tree fndecl) member_init_list = tree_cons (field, init, member_init_list); } - finish_mem_initializers (member_init_list); + finish_mem_initializers (member_init_list, skip_vbases); } } @@ -784,6 +784,7 @@ synthesize_method (tree fndecl) location_t save_input_location = input_location; int error_count = errorcount; int warning_count = warningcount + werrorcount; + bool skip_vbases = false; /* Reset the source location, we might have been previously deferred, and thus have saved where we were first needed. */ @@ -794,7 +795,12 @@ synthesize_method (tree fndecl) cloned function instead. Doing so will automatically fill in the body for the clone. */ if (DECL_CLONED_FUNCTION_P (fndecl)) - fndecl = DECL_CLONED_FUNCTION (fndecl); + { + skip_vbases = (DECL_DELETED_FN (fndecl) + && DECL_BASE_UNDELETED_FN (fndecl)); + if (!skip_vbases) + fndecl = DECL_CLONED_FUNCTION (fndecl); + } /* We may be in the middle of deferred access check. Disable it now. */ @@ -819,9 +825,9 @@ synthesize_method (tree fndecl) { tree arg_chain = FUNCTION_FIRST_USER_PARMTYPE (fndecl); if (arg_chain != void_list_node) - do_build_copy_constructor (fndecl); + do_build_copy_constructor (fndecl, skip_vbases); else - finish_mem_initializers (NULL_TREE); + finish_mem_initializers (NULL_TREE, skip_vbases); } /* If we haven't yet generated the body of the function, just @@ -1319,16 +1325,20 @@ walk_field_subobs (tree fields, tree fnn } } -/* The caller wants to generate an implicit declaration of SFK for CTYPE - which is const if relevant and CONST_P is set. If spec_p, trivial_p and - deleted_p are non-null, set their referent appropriately. If diag is - true, we're either being called from maybe_explain_implicit_delete to - give errors, or if constexpr_p is non-null, from - explain_invalid_constexpr_fn. */ +/* The caller wants to generate an implicit declaration of SFK for + CTYPE which is const if relevant and CONST_P is set. If SPEC_P, + TRIVIAL_P, DELETED_P, VBASE_DELETED_P or CONSTEXPR_P are non-null, + set their referent appropriately. VBASE_DELETED_P is used for + virtual bases, which is relevant in C++ 11 where a base ctor + doesn't need to care about deleted ctors of virtual bases. If diag + is true, we're either being called from + maybe_explain_implicit_delete to give errors, or if constexpr_p is + non-null, from explain_invalid_constexpr_fn. */ static void synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, - tree *spec_p, bool *trivial_p, bool *deleted_p, + tree *spec_p, bool *trivial_p, + bool *deleted_p, bool *vbase_deleted_p, bool *constexpr_p, bool diag, tree inherited_base, tree inherited_parms) { @@ -1358,6 +1368,9 @@ synthesized_method_walk (tree ctype, spe *deleted_p = false; } + if (vbase_deleted_p) + *vbase_deleted_p = false; + ctor_p = false; assign_p = false; check_vdtor = false; @@ -1534,27 +1547,34 @@ synthesized_method_walk (tree ctype, spe } vbases = CLASSTYPE_VBASECLASSES (ctype); - if (vec_safe_is_empty (vbases)) - /* No virtual bases to worry about. */; - else if (!assign_p) + if (!assign_p && !vec_safe_is_empty (vbases)) { + /* Check virtual base cdtors. */ if (constexpr_p) *constexpr_p = false; + + /* Point at deleted_p, if we don't care for the vbase_deleted + distinction. */ + if (!ctor_p || !vbase_deleted_p || cxx_dialect < cxx14 + || !ABSTRACT_CLASS_TYPE_P (ctype)) + vbase_deleted_p = deleted_p; + FOR_EACH_VEC_ELT (*vbases, i, base_binfo) { tree basetype = BINFO_TYPE (base_binfo); if (copy_arg_p) argtype = build_stub_type (basetype, quals, move_p); - rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain); + rval = locate_fn_flags (base_binfo, fnname, argtype, + flags, complain); - process_subob_fn (rval, spec_p, trivial_p, deleted_p, + process_subob_fn (rval, spec_p, trivial_p, vbase_deleted_p, constexpr_p, diag, basetype); if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype)) { rval = locate_fn_flags (base_binfo, complete_dtor_identifier, NULL_TREE, flags, complain); process_subob_fn (rval, NULL, NULL, - deleted_p, NULL, false, + vbase_deleted_p, NULL, false, basetype, /*dtor_from_ctor*/true); } } @@ -1594,7 +1614,7 @@ get_defaulted_eh_spec (tree decl) bool const_p = CP_TYPE_CONST_P (non_reference (parm_type)); tree spec = empty_except_spec; synthesized_method_walk (ctype, sfk, const_p, &spec, NULL, NULL, - NULL, false, DECL_INHERITED_CTOR_BASE (decl), + NULL, NULL, false, DECL_INHERITED_CTOR_BASE (decl), parms); return spec; } @@ -1662,15 +1682,15 @@ maybe_explain_implicit_delete (tree decl bool deleted_p = false; tree scope = push_scope (ctype); - synthesized_method_walk (ctype, sfk, const_p, - &raises, NULL, &deleted_p, NULL, false, + synthesized_method_walk (ctype, sfk, const_p, &raises, + NULL, &deleted_p, NULL, NULL, false, DECL_INHERITED_CTOR_BASE (decl), parms); if (deleted_p) { inform (DECL_SOURCE_LOCATION (decl), "%q#D is implicitly deleted because the default " "definition would be ill-formed:", decl); - synthesized_method_walk (ctype, sfk, const_p, + synthesized_method_walk (ctype, sfk, const_p, NULL, NULL, NULL, NULL, NULL, true, DECL_INHERITED_CTOR_BASE (decl), parms); } @@ -1704,7 +1724,7 @@ explain_implicit_non_constexpr (tree dec bool dummy; synthesized_method_walk (DECL_CLASS_CONTEXT (decl), special_function_p (decl), const_p, - NULL, NULL, NULL, &dummy, true, + NULL, NULL, NULL, NULL, &dummy, true, DECL_INHERITED_CTOR_BASE (decl), FUNCTION_FIRST_USER_PARMTYPE (decl)); } @@ -1720,8 +1740,8 @@ deduce_inheriting_ctor (tree decl) tree spec; bool trivial, constexpr_, deleted; synthesized_method_walk (DECL_CONTEXT (decl), sfk_inheriting_constructor, - false, &spec, &trivial, &deleted, &constexpr_, - /*diag*/false, + false, &spec, &trivial, &deleted, NULL, + &constexpr_, /*diag*/false, DECL_INHERITED_CTOR_BASE (decl), FUNCTION_FIRST_USER_PARMTYPE (decl)); DECL_DELETED_FN (decl) = deleted; @@ -1748,7 +1768,7 @@ implicitly_declare_fn (special_function_ tree this_parm; tree name; HOST_WIDE_INT saved_processing_template_decl; - bool deleted_p; + bool deleted_p, vbase_deleted_p; bool constexpr_p; /* Because we create declarations for implicitly declared functions @@ -1841,15 +1861,16 @@ implicitly_declare_fn (special_function_ { raises = unevaluated_noexcept_spec (); synthesized_method_walk (type, kind, const_p, NULL, &trivial_p, - &deleted_p, &constexpr_p, false, - inherited_base, inherited_parms); + &deleted_p, &vbase_deleted_p, &constexpr_p, + false, inherited_base, inherited_parms); } else synthesized_method_walk (type, kind, const_p, &raises, &trivial_p, - &deleted_p, &constexpr_p, false, + &deleted_p, NULL, &constexpr_p, false, inherited_base, inherited_parms); + /* Don't bother marking a deleted constructor as constexpr. */ - if (deleted_p) + if (deleted_p || vbase_deleted_p) constexpr_p = false; /* A trivial copy/move constructor is also a constexpr constructor, unless the class has virtual bases (7.1.5p4). */ @@ -1929,8 +1950,16 @@ implicitly_declare_fn (special_function_ DECL_DEFAULTED_FN (fn) = 1; if (cxx_dialect >= cxx11) { - DECL_DELETED_FN (fn) = deleted_p; + if (!deleted_p && vbase_deleted_p) + { + /* The general ctor pattern is deleted, but the instance for + a base is not (because the cause of the deletion is a + missing vbase ctor). */ + DECL_BASE_UNDELETED_FN (fn) = true; + deleted_p = true; + } DECL_DECLARED_CONSTEXPR_P (fn) = constexpr_p; + DECL_DELETED_FN (fn) = deleted_p; } DECL_EXTERNAL (fn) = true; DECL_NOT_REALLY_EXTERN (fn) = 1; @@ -1962,7 +1991,7 @@ implicitly_declare_fn (special_function_ location_t loc = input_location; input_location = DECL_SOURCE_LOCATION (fn); synthesized_method_walk (type, kind, const_p, - NULL, NULL, NULL, NULL, true, + NULL, NULL, NULL, NULL, NULL, true, NULL_TREE, NULL_TREE); input_location = loc; } Index: cp/parser.c =================================================================== --- cp/parser.c (revision 240596) +++ cp/parser.c (working copy) @@ -13648,7 +13648,7 @@ cp_parser_ctor_initializer_opt (cp_parse { /* Do default initialization of any bases and members. */ if (DECL_CONSTRUCTOR_P (current_function_decl)) - finish_mem_initializers (NULL_TREE); + finish_mem_initializers (NULL_TREE, false); return false; } @@ -13745,7 +13745,7 @@ cp_parser_mem_initializer_list (cp_parse /* Perform semantic analysis. */ if (DECL_CONSTRUCTOR_P (current_function_decl)) - finish_mem_initializers (mem_initializer_list); + finish_mem_initializers (mem_initializer_list, false); } /* Parse a mem-initializer. Index: cp/pt.c =================================================================== --- cp/pt.c (revision 240596) +++ cp/pt.c (working copy) @@ -15231,7 +15231,7 @@ tsubst_expr (tree t, tree args, tsubst_f case CTOR_INITIALIZER: finish_mem_initializers (tsubst_initializer_list - (TREE_OPERAND (t, 0), args)); + (TREE_OPERAND (t, 0), args), false); break; case RETURN_EXPR: Index: cp/semantics.c =================================================================== --- cp/semantics.c (revision 240596) +++ cp/semantics.c (working copy) @@ -1605,7 +1605,7 @@ finish_eh_cleanup (tree cleanup) emit_mem_initializers. */ void -finish_mem_initializers (tree mem_inits) +finish_mem_initializers (tree mem_inits, bool skip_vbases) { /* Reorder the MEM_INITS so that they are in the order they appeared in the source program. */ @@ -1631,7 +1631,7 @@ finish_mem_initializers (tree mem_inits) CTOR_INITIALIZER, mem_inits)); } else - emit_mem_initializers (mem_inits); + emit_mem_initializers (mem_inits, skip_vbases); } /* Obfuscate EXPR if it looks like an id-expression or member access so Index: testsuite/g++.dg/cpp0x/pr66443-cxx11.C =================================================================== --- testsuite/g++.dg/cpp0x/pr66443-cxx11.C (nonexistent) +++ testsuite/g++.dg/cpp0x/pr66443-cxx11.C (working copy) @@ -0,0 +1,30 @@ +// { dg-do compile { target c++11_only } } + +// pr c++/66443 it is still ill-formed in C++ 11 for a synthesized +// ctor that's deleted only because of virtual base construction + +static bool a_made; + +struct A { // { dg-message "candidate" } + A( int ) { a_made = true; } // { dg-message "candidate" } +}; + +struct B: virtual A { // { dg-message "no matching function" } + int m; + virtual void Frob () = 0; +}; + +class C: public B { +public: + C(); + virtual void Frob (); +}; + +void C::Frob () +{ +} + +C::C () + : A( 1 ) // { dg-error "deleted function" } +{ } + Index: testsuite/g++.dg/cpp1y/pr66443-cxx14.C =================================================================== --- testsuite/g++.dg/cpp1y/pr66443-cxx14.C (nonexistent) +++ testsuite/g++.dg/cpp1y/pr66443-cxx14.C (working copy) @@ -0,0 +1,47 @@ +// { dg-do run { target c++14 } } + +// pr c++/66443 a synthesized ctor of an abstract class that's deleted +// only because of virtual base construction doesn't stop a derived +// class using it as a base object constructor (provided it has a +// suitable ctor invocation of the virtual base). + +static int a_made; + +struct A { + A *m_a = this; + A (int) { a_made++; } +}; + +struct B : virtual A { + A *m_b = this; + virtual bool Ok () = 0; // abstract +}; + +struct C : B { + // C::m_c is placed where a complete B object would put A + int m_c = 1729; +public: + C(); + virtual bool Ok (); +}; + +bool C::Ok () +{ + // check everyone agreed on where A is + return a_made == 1 && m_a == this && m_b == this && m_c == 1729; +} + +C::C () + : A (1) // Explicit call of A's ctor +{ } + +bool Ok (C &c) +{ +} + +int main () +{ + C c; + + return !c.Ok (); +} Index: testsuite/g++.dg/cpp1y/pr66443-cxx14-2.C =================================================================== --- testsuite/g++.dg/cpp1y/pr66443-cxx14-2.C (nonexistent) +++ testsuite/g++.dg/cpp1y/pr66443-cxx14-2.C (working copy) @@ -0,0 +1,29 @@ +// { dg-do compile { target c++14 } } + +// pr c++/66443 a synthesized ctor of an abstract class that's deleted +// only because of virtual base construction doesn't stop a derived +// class using it as a base object constructor (provided it has a +// suitable ctor invocation of the virtual base). + +// However we should still complain if the intermediate base is a +// non-abstract type. + +static int a_made; + +struct A { + A *m_a = this; + A (int) { a_made++; } +}; + +struct B : virtual A { // { dg-error "no matching function" } + A *m_b = this; + virtual bool Ok (); // not abstract +}; + +bool B::Ok () +{ + return false; +} + + +B b; // { dg-error "deleted" }