From patchwork Sat May 21 21:57:21 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 96712 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 96160B71B4 for ; Sun, 22 May 2011 07:57:43 +1000 (EST) Received: (qmail 12204 invoked by alias); 21 May 2011 21:57:42 -0000 Received: (qmail 12196 invoked by uid 22791); 21 May 2011 21:57:41 -0000 X-SWARE-Spam-Status: No, hits=-6.2 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_FN, TW_KF, TW_SF, T_RP_MATCHES_RCVD 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; Sat, 21 May 2011 21:57:23 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p4LLvMnD010848 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Sat, 21 May 2011 17:57:22 -0400 Received: from [127.0.0.1] ([10.3.113.3]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p4LLvMYV021805 for ; Sat, 21 May 2011 17:57:22 -0400 Message-ID: <4DD83541.2040403@redhat.com> Date: Sat, 21 May 2011 17:57:21 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc14 Lightning/1.0b2 Thunderbird/3.1.10 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for c++/48945 (defining static constexpr fn outside class) 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 revert_static_member_fn was complaining about the implicit 'const' on a constexpr non-static member function even though it wasn't actually written. The first patch changes the compiler to allow 'const' on a constexpr function, which fixes the testcase; the second patch also allows the compiler to complain when the user wrote 'const' explicitly. Tested x86_64-pc-linux-gnu. First patch applied to trunk and 4.6, second trunk only. commit 0dd08faa4bad75ac99e29efdae5acbb2e7f174be Author: Jason Merrill Date: Fri May 20 18:17:39 2011 -0400 PR c++/48945 * decl.c (revert_static_member_fn): Ignore const on constexpr fn. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index eae7d8e..598af1c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13575,10 +13575,15 @@ void revert_static_member_fn (tree decl) { tree stype = static_fn_type (decl); + cp_cv_quals quals = type_memfn_quals (stype); - if (type_memfn_quals (stype) != TYPE_UNQUALIFIED) + if (quals != TYPE_UNQUALIFIED) { - error ("static member function %q#D declared with type qualifiers", decl); + if (quals == TYPE_QUAL_CONST && DECL_DECLARED_CONSTEXPR_P (decl)) + /* The const was implicit, don't complain. */; + else + error ("static member function %q#D declared with type qualifiers", + decl); stype = apply_memfn_quals (stype, TYPE_UNQUALIFIED); } TREE_TYPE (decl) = stype; diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-static7.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-static7.C new file mode 100644 index 0000000..ba4a251 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-static7.C @@ -0,0 +1,8 @@ +// PR c++/48945 +// { dg-options -std=c++0x } + +struct A { + static constexpr bool is(); +}; + +constexpr bool A::is() { return true; } commit bf3db2f49e7927afa0293379700d488dcb98e2c7 Author: Jason Merrill Date: Fri May 20 23:32:39 2011 -0400 PR c++/48945 * decl.c (grokdeclarator): Don't add set const function-cv-qual for constexpr fns to memfn_quals, just add it to the type. (revert_static_member_fn): Don't complain about quals. (check_static_quals): New. (grokfndecl): Call it. (start_preparsed_function): Don't call revert_static_member_fn. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 598af1c..733157a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6960,6 +6960,17 @@ build_this_parm (tree type, cp_cv_quals quals) return parm; } +/* DECL is a static member function. Complain if it was declared + with function-cv-quals. */ + +static void +check_static_quals (tree decl, cp_cv_quals quals) +{ + if (quals != TYPE_UNQUALIFIED) + error ("static member function %q#D declared with type qualifiers", + decl); +} + /* CTYPE is class type, or null if non-class. TYPE is type this FUNCTION_DECL should have, either FUNCTION_TYPE or METHOD_TYPE. @@ -7241,6 +7252,9 @@ grokfndecl (tree ctype, if (decl == error_mark_node) return NULL_TREE; + if (DECL_STATIC_FUNCTION_P (decl)) + check_static_quals (decl, quals); + if (attrlist) { cplus_decl_attributes (&decl, *attrlist, 0); @@ -7290,9 +7304,11 @@ grokfndecl (tree ctype, if (DECL_STATIC_FUNCTION_P (old_decl) && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) - /* Remove the `this' parm added by grokclassfn. - XXX Isn't this done in start_function, too? */ - revert_static_member_fn (decl); + { + /* Remove the `this' parm added by grokclassfn. */ + revert_static_member_fn (decl); + check_static_quals (decl, quals); + } if (DECL_ARTIFICIAL (old_decl)) { error ("definition of implicitly-declared %qD", old_decl); @@ -9356,12 +9372,6 @@ grokdeclarator (const cp_declarator *declarator, if (ctype == NULL_TREE && decl_context == FIELD && friendp == 0) ctype = current_class_type; - /* A constexpr non-static member function is implicitly const. */ - if (constexpr_p && ctype && staticp == 0 - && TREE_CODE (type) == FUNCTION_TYPE - && sfk != sfk_constructor && sfk != sfk_destructor) - memfn_quals |= TYPE_QUAL_CONST; - /* Now TYPE has the actual type. */ if (returned_attrs) @@ -9733,7 +9743,12 @@ grokdeclarator (const cp_declarator *declarator, if (ctype && TREE_CODE (type) == FUNCTION_TYPE && staticp < 2 && !NEW_DELETE_OPNAME_P (unqualified_id)) - type = build_memfn_type (type, ctype, memfn_quals); + { + cp_cv_quals real_quals = memfn_quals; + if (constexpr_p && sfk != sfk_constructor && sfk != sfk_destructor) + real_quals |= TYPE_QUAL_CONST; + type = build_memfn_type (type, ctype, real_quals); + } { tree decl; @@ -12373,12 +12388,8 @@ start_preparsed_function (tree decl1, tree attrs, int flags) /* Sometimes we don't notice that a function is a static member, and build a METHOD_TYPE for it. Fix that up now. */ - if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1) - && TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE) - { - revert_static_member_fn (decl1); - ctype = NULL_TREE; - } + gcc_assert (!(ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1) + && TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE)); /* Set up current_class_type, and enter the scope of the class, if appropriate. */ @@ -13578,14 +13589,8 @@ revert_static_member_fn (tree decl) cp_cv_quals quals = type_memfn_quals (stype); if (quals != TYPE_UNQUALIFIED) - { - if (quals == TYPE_QUAL_CONST && DECL_DECLARED_CONSTEXPR_P (decl)) - /* The const was implicit, don't complain. */; - else - error ("static member function %q#D declared with type qualifiers", - decl); - stype = apply_memfn_quals (stype, TYPE_UNQUALIFIED); - } + stype = apply_memfn_quals (stype, TYPE_UNQUALIFIED); + TREE_TYPE (decl) = stype; if (DECL_ARGUMENTS (decl)) diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-static7.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-static7.C index ba4a251..e46ddaf 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-static7.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-static7.C @@ -3,6 +3,8 @@ struct A { static constexpr bool is(); + static constexpr bool is_not(); }; constexpr bool A::is() { return true; } +constexpr bool A::is_not() const { return true; } // { dg-error "static" }